@flopay/react 1.0.3 → 1.1.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.cjs CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  CardExpiryElement: () => CardExpiryElement,
37
37
  CardNumberElement: () => CardNumberElement,
38
38
  CheckoutForm: () => CheckoutForm,
39
+ DirectPayPalButton: () => DirectPayPalButton,
39
40
  FloPayAutomaticPaymentButton: () => FloPayAutomaticPaymentButton,
40
41
  FloPayCheckout: () => FloPayCheckout,
41
42
  FloPayProvider: () => FloPayProvider,
@@ -151,9 +152,9 @@ function FloPayProvider({
151
152
  }
152
153
 
153
154
  // src/flopay-checkout.tsx
154
- var import_react8 = __toESM(require("react"), 1);
155
- var import_js3 = require("@flopay/js");
156
- var import_shared7 = require("@flopay/shared");
155
+ var import_react9 = __toESM(require("react"), 1);
156
+ var import_js4 = require("@flopay/js");
157
+ var import_shared8 = require("@flopay/shared");
157
158
 
158
159
  // src/card-button-content.tsx
159
160
  var import_react3 = require("react");
@@ -284,9 +285,9 @@ var AddressElement = createElementComponent("address", "AddressElement");
284
285
 
285
286
  // src/split-card-form.tsx
286
287
  var import_react_stripe_js = require("@stripe/react-stripe-js");
287
- var import_shared4 = require("@flopay/shared");
288
- var import_js = require("@flopay/js");
289
- var import_react7 = require("react");
288
+ var import_shared5 = require("@flopay/shared");
289
+ var import_js2 = require("@flopay/js");
290
+ var import_react8 = require("react");
290
291
 
291
292
  // src/hooks.ts
292
293
  var import_react5 = require("react");
@@ -494,15 +495,37 @@ function mergeInlineSessionPatch(params, patch) {
494
495
  };
495
496
  }
496
497
  function buildSyntheticSession(params, checkoutModeOverride) {
497
- const totalAmount = [
498
- ...(params.items ?? []).map((item) => item.overrideAmount ?? item.totalAmount ?? 0),
499
- ...(params.subscriptions ?? []).map((subscription) => subscription.overrideAmount ?? subscription.totalAmount ?? 0)
500
- ].reduce((sum, value) => sum + value, 0);
501
- const currency = params.currency ?? params.items?.find((i) => i.currency)?.currency ?? params.subscriptions?.find((s) => s.currency)?.currency ?? "USD";
498
+ const inputProducts = params.products ?? [
499
+ ...(params.subscriptions ?? []).map((s) => ({
500
+ type: "subscription",
501
+ code: s.code ?? s.providerPlanId,
502
+ name: s.subscriptionName ?? s.providerPlanName ?? s.code ?? s.providerPlanId ?? null,
503
+ quantity: s.quantity ?? 1,
504
+ totalAmount: s.totalAmount,
505
+ overrideAmount: s.overrideAmount,
506
+ currency: s.currency,
507
+ metadata: s.metadata
508
+ })),
509
+ ...(params.items ?? []).map((i) => ({
510
+ type: "item",
511
+ code: i.code ?? i.providerItemId,
512
+ name: i.itemName ?? i.providerItemName ?? i.code ?? i.providerItemId ?? null,
513
+ quantity: i.quantity ?? 1,
514
+ totalAmount: i.totalAmount,
515
+ overrideAmount: i.overrideAmount,
516
+ currency: i.currency,
517
+ metadata: i.metadata
518
+ }))
519
+ ];
520
+ const totalAmount = inputProducts.reduce(
521
+ (sum, p) => sum + (p.overrideAmount ?? p.totalAmount ?? 0),
522
+ 0
523
+ );
524
+ const currency = params.currency ?? inputProducts.find((p) => p.currency)?.currency ?? "USD";
502
525
  return {
503
526
  id: "",
504
527
  clientSecret: "",
505
- mode: "payment",
528
+ mode: inputProducts.some((p) => p.type === "subscription") ? "subscription" : "payment",
506
529
  amount: Math.round(totalAmount * 100),
507
530
  currency,
508
531
  status: "open",
@@ -520,40 +543,18 @@ function buildSyntheticSession(params, checkoutModeOverride) {
520
543
  successUrl: params.successUrl,
521
544
  cancelUrl: params.cancelUrl,
522
545
  checkoutMode: checkoutModeOverride ?? params.checkoutMode ?? "full",
523
- items: (params.items ?? []).map((item, idx) => {
524
- const code = item.code ?? item.providerItemId;
525
- const itemName = item.itemName ?? item.providerItemName ?? code;
526
- return {
527
- uuid: `synthetic-item-${idx}`,
528
- checkoutSessionId: "",
529
- code,
530
- providerItemId: code,
531
- itemName,
532
- providerItemName: itemName,
533
- quantity: item.quantity ?? 1,
534
- totalAmount: item.totalAmount,
535
- overrideAmount: item.overrideAmount ?? null,
536
- currency: item.currency ?? currency,
537
- metadata: item.metadata ?? null
538
- };
539
- }),
540
- subscriptions: (params.subscriptions ?? []).map((subscription, idx) => {
541
- const code = subscription.code ?? subscription.providerPlanId;
542
- const subscriptionName = subscription.subscriptionName ?? subscription.providerPlanName ?? code;
543
- return {
544
- uuid: `synthetic-sub-${idx}`,
545
- checkoutSessionId: "",
546
- code,
547
- providerPlanId: code,
548
- subscriptionName,
549
- providerPlanName: subscriptionName,
550
- quantity: subscription.quantity ?? 1,
551
- totalAmount: subscription.totalAmount,
552
- overrideAmount: subscription.overrideAmount ?? null,
553
- currency: subscription.currency ?? currency,
554
- metadata: subscription.metadata ?? null
555
- };
556
- })
546
+ products: inputProducts.map((p, idx) => ({
547
+ uuid: `synthetic-${p.type}-${idx}`,
548
+ checkoutSessionId: "",
549
+ type: p.type,
550
+ code: p.code,
551
+ name: p.name ?? null,
552
+ quantity: p.quantity ?? 1,
553
+ totalAmount: p.totalAmount,
554
+ overrideAmount: p.overrideAmount ?? null,
555
+ currency: p.currency ?? currency,
556
+ metadata: p.metadata ?? null
557
+ }))
557
558
  };
558
559
  }
559
560
  function mergeAccountPatch(base, patch) {
@@ -581,9 +582,25 @@ function readString(payload, key) {
581
582
  const value = payload?.[key];
582
583
  return typeof value === "string" && value.trim() ? value : void 0;
583
584
  }
585
+ var FRIENDLY_MESSAGE_OVERRIDES = [
586
+ {
587
+ match: /^paypal authorization required\.?$/i,
588
+ replacement: "For your additional security, please re-authenticate this payment via PayPal."
589
+ }
590
+ ];
591
+ function applyFriendlyMessageOverride(message) {
592
+ if (typeof message !== "string") return message ?? void 0;
593
+ const trimmed = message.trim();
594
+ if (!trimmed) return message;
595
+ for (const { match, replacement } of FRIENDLY_MESSAGE_OVERRIDES) {
596
+ if (match.test(trimmed)) return replacement;
597
+ }
598
+ return message;
599
+ }
584
600
  function buildFloPayApiError(payload, fallbackMessage) {
585
601
  const nestedError = isRecord(payload?.error) ? payload.error : null;
586
- const message = readString(payload, "message") ?? readString(nestedError, "message") ?? fallbackMessage;
602
+ const rawMessage = readString(payload, "message") ?? readString(nestedError, "message") ?? fallbackMessage;
603
+ const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
587
604
  const code = readString(payload, "code") ?? readString(payload, "gatewayErrorCode") ?? readString(nestedError, "code");
588
605
  const declineCode = readString(payload, "declineCode") ?? readString(payload, "gatewayDeclineReason") ?? readString(payload, "decline_code") ?? readString(nestedError, "decline_code");
589
606
  return new import_shared3.FloPayError(message, "api_error", {
@@ -688,11 +705,565 @@ function isInAppBrowser(userAgent) {
688
705
  return false;
689
706
  }
690
707
 
691
- // src/split-card-form.tsx
692
- var import_shared5 = require("@flopay/shared");
708
+ // src/direct-paypal-button.tsx
709
+ var import_react7 = require("react");
710
+ var import_paypal_js = require("@paypal/paypal-js");
711
+ var import_js = require("@flopay/js");
712
+ var import_shared4 = require("@flopay/shared");
693
713
  var import_jsx_runtime5 = require("react/jsx-runtime");
714
+ var DEFAULT_BUTTON_HEIGHT = 45;
715
+ function DirectPayPalButton({
716
+ sessionId,
717
+ billingApiUrl,
718
+ email,
719
+ clientId,
720
+ environment,
721
+ currency,
722
+ isSubscription,
723
+ onTokenizedBody,
724
+ onComplete,
725
+ onErrorChange,
726
+ onDecline,
727
+ isProcessing = false,
728
+ onLoadStateChange,
729
+ onButtonClick,
730
+ runBeforeButtonClick,
731
+ session,
732
+ existingOrderId,
733
+ debug = false
734
+ }) {
735
+ const containerRef = (0, import_react7.useRef)(null);
736
+ const [ready, setReady] = (0, import_react7.useState)(false);
737
+ const [failed, setFailed] = (0, import_react7.useState)(false);
738
+ const [submitting, setSubmitting] = (0, import_react7.useState)(false);
739
+ const baseUrl = (0, import_react7.useMemo)(() => billingApiUrl.replace(/\/+$/, ""), [billingApiUrl]);
740
+ const [debugLines, setDebugLines] = (0, import_react7.useState)([]);
741
+ const appendDebug = (line) => {
742
+ if (!debug) return;
743
+ setDebugLines((prev) => [...prev, `${(/* @__PURE__ */ new Date()).toISOString().slice(11, 23)} ${line}`]);
744
+ };
745
+ const onTokenizedBodyRef = (0, import_react7.useRef)(onTokenizedBody);
746
+ const onCompleteRef = (0, import_react7.useRef)(onComplete);
747
+ const onErrorChangeRef = (0, import_react7.useRef)(onErrorChange);
748
+ const onDeclineRef = (0, import_react7.useRef)(onDecline);
749
+ const onButtonClickRef = (0, import_react7.useRef)(onButtonClick);
750
+ const onLoadStateChangeRef = (0, import_react7.useRef)(onLoadStateChange);
751
+ const runBeforeButtonClickRef = (0, import_react7.useRef)(runBeforeButtonClick);
752
+ const sessionRef = (0, import_react7.useRef)(session);
753
+ const emailRef = (0, import_react7.useRef)(email);
754
+ const beforeClickRef = (0, import_react7.useRef)(null);
755
+ (0, import_react7.useEffect)(() => {
756
+ onTokenizedBodyRef.current = onTokenizedBody;
757
+ }, [onTokenizedBody]);
758
+ (0, import_react7.useEffect)(() => {
759
+ onCompleteRef.current = onComplete;
760
+ }, [onComplete]);
761
+ (0, import_react7.useEffect)(() => {
762
+ onErrorChangeRef.current = onErrorChange;
763
+ }, [onErrorChange]);
764
+ (0, import_react7.useEffect)(() => {
765
+ onDeclineRef.current = onDecline;
766
+ }, [onDecline]);
767
+ (0, import_react7.useEffect)(() => {
768
+ onButtonClickRef.current = onButtonClick;
769
+ }, [onButtonClick]);
770
+ (0, import_react7.useEffect)(() => {
771
+ onLoadStateChangeRef.current = onLoadStateChange;
772
+ }, [onLoadStateChange]);
773
+ (0, import_react7.useEffect)(() => {
774
+ runBeforeButtonClickRef.current = runBeforeButtonClick;
775
+ }, [runBeforeButtonClick]);
776
+ (0, import_react7.useEffect)(() => {
777
+ sessionRef.current = session;
778
+ }, [session]);
779
+ (0, import_react7.useEffect)(() => {
780
+ emailRef.current = email;
781
+ }, [email]);
782
+ (0, import_react7.useEffect)(() => {
783
+ onLoadStateChangeRef.current?.(ready && !failed);
784
+ }, [ready, failed]);
785
+ const normalizedEnv = (0, import_shared4.normalizeGatewayEnvironment)(environment);
786
+ (0, import_react7.useEffect)(() => {
787
+ const maskedClient = clientId ? `${clientId.slice(0, 6)}\u2026(len ${clientId.length})` : "(empty)";
788
+ const ua = typeof navigator !== "undefined" ? navigator.userAgent : "(no navigator)";
789
+ appendDebug(`mount clientId=${maskedClient} env=${environment ?? "(unset)"}\u2192${normalizedEnv ?? "live"} ccy=${currency} sub=${isSubscription}`);
790
+ appendDebug(`ua=${ua.slice(0, 80)}${ua.length > 80 ? "\u2026" : ""}`);
791
+ if (!clientId) {
792
+ appendDebug("FAIL: clientId empty \u2014 gateway misconfigured");
793
+ setFailed(true);
794
+ onErrorChangeRef.current?.("Direct PayPal gateway is misconfigured.");
795
+ return;
796
+ }
797
+ if (!containerRef.current) {
798
+ appendDebug("FAIL: containerRef not attached");
799
+ return;
800
+ }
801
+ let cancelled = false;
802
+ let activeButtons = null;
803
+ let rendered = false;
804
+ const container = containerRef.current;
805
+ let containerObserver = null;
806
+ let perfObserver = null;
807
+ const watchdogTimers = [];
808
+ const formatDims = (el) => {
809
+ if (!el || typeof el.getBoundingClientRect !== "function") return "(no rect)";
810
+ const rect = el.getBoundingClientRect();
811
+ return `${Math.round(rect.width)}\xD7${Math.round(rect.height)}`;
812
+ };
813
+ const classifyIframeSrc = (raw) => {
814
+ if (!raw) return "(empty)";
815
+ try {
816
+ const url = new URL(raw, typeof window !== "undefined" ? window.location.href : "https://localhost");
817
+ const path = url.pathname.toLowerCase();
818
+ if (path.includes("checkcaptcha") || path.includes("captcha")) return `CAPTCHA(${url.host}${path})`;
819
+ if (path.includes("risk") || path.includes("challenge")) return `RISK(${url.host}${path})`;
820
+ if (path.includes("smart/buttons")) return `smart-buttons(${url.host})`;
821
+ return `${url.host}${path}`.slice(0, 100);
822
+ } catch {
823
+ return raw.slice(0, 80);
824
+ }
825
+ };
826
+ const describeIframe = (frame) => {
827
+ const src = frame.getAttribute("src");
828
+ const srcdoc = frame.getAttribute("srcdoc");
829
+ const name = frame.getAttribute("name");
830
+ const sandbox = frame.getAttribute("sandbox");
831
+ const parts = [];
832
+ if (src) parts.push(`src=${classifyIframeSrc(src)}`);
833
+ if (srcdoc) parts.push(`srcdoc[${srcdoc.length}ch]`);
834
+ if (!src && !srcdoc) parts.push("src=(empty) srcdoc=(empty)");
835
+ if (name) parts.push(`name=${name.slice(0, 40)}`);
836
+ if (sandbox !== null) parts.push(`sandbox="${sandbox.slice(0, 40)}"`);
837
+ return parts.join(" ");
838
+ };
839
+ const inspectFrameContent = (frame) => {
840
+ if (!(frame instanceof HTMLIFrameElement)) return "";
841
+ try {
842
+ const cd = frame.contentDocument;
843
+ if (!cd) return "cd=null";
844
+ const bodyChildren = cd.body?.children.length ?? 0;
845
+ const bodyLen = cd.body?.innerHTML.length ?? 0;
846
+ const headLen = cd.head?.innerHTML.length ?? 0;
847
+ return `cd=same-origin readyState=${cd.readyState} body[${bodyChildren}children,${bodyLen}ch] head[${headLen}ch]`;
848
+ } catch (err) {
849
+ return `cd=cross-origin(${err.message.slice(0, 30)})`;
850
+ }
851
+ };
852
+ const errorMessages = [];
853
+ const onWindowError = (ev) => {
854
+ const msg = ev.message ?? String(ev.error ?? "(no message)");
855
+ if (msg && (msg.toLowerCase().includes("paypal") || msg.toLowerCase().includes("zoid") || msg.toLowerCase().includes("postrobot") || msg.toLowerCase().includes("storage"))) {
856
+ appendDebug(`window:error ${msg.slice(0, 140)}`);
857
+ errorMessages.push(msg);
858
+ }
859
+ };
860
+ const onUnhandledRejection = (ev) => {
861
+ const reason = ev.reason instanceof Error ? ev.reason.message : String(ev.reason ?? "(no reason)");
862
+ if (reason && (reason.toLowerCase().includes("paypal") || reason.toLowerCase().includes("zoid") || reason.toLowerCase().includes("postrobot") || reason.toLowerCase().includes("storage"))) {
863
+ appendDebug(`window:rejection ${reason.slice(0, 140)}`);
864
+ errorMessages.push(reason);
865
+ }
866
+ };
867
+ if (debug && typeof window !== "undefined") {
868
+ window.addEventListener("error", onWindowError);
869
+ window.addEventListener("unhandledrejection", onUnhandledRejection);
870
+ }
871
+ const paypalRequestCount = { value: 0 };
872
+ if (debug && typeof PerformanceObserver !== "undefined") {
873
+ try {
874
+ perfObserver = new PerformanceObserver((list) => {
875
+ for (const entry of list.getEntries()) {
876
+ if (!entry.name.toLowerCase().includes("paypal")) continue;
877
+ paypalRequestCount.value += 1;
878
+ const dur = Math.round(entry.duration);
879
+ appendDebug(`net ${dur}ms ${entry.name.slice(0, 90)}`);
880
+ }
881
+ });
882
+ perfObserver.observe({ type: "resource", buffered: true });
883
+ } catch {
884
+ }
885
+ }
886
+ const stopDiagnostics = () => {
887
+ containerObserver?.disconnect();
888
+ containerObserver = null;
889
+ perfObserver?.disconnect();
890
+ perfObserver = null;
891
+ while (watchdogTimers.length) clearTimeout(watchdogTimers.pop());
892
+ if (debug && typeof window !== "undefined") {
893
+ window.removeEventListener("error", onWindowError);
894
+ window.removeEventListener("unhandledrejection", onUnhandledRejection);
895
+ }
896
+ };
897
+ const isZoidLifecycleMessage = (message) => {
898
+ if (!message) return false;
899
+ const lower = message.toLowerCase();
900
+ return lower.includes("zoid destroyed") || lower.includes("destroyed all components") || lower.includes("window closed") || lower.includes("detected container element removed");
901
+ };
902
+ const forwardError = (message) => {
903
+ if (cancelled) return;
904
+ if (isZoidLifecycleMessage(message)) return;
905
+ const friendly = applyFriendlyMessageOverride(message) ?? message;
906
+ onErrorChangeRef.current?.(friendly);
907
+ };
908
+ const markRenderFailed = (message) => {
909
+ if (cancelled) return;
910
+ if (isZoidLifecycleMessage(message)) {
911
+ appendDebug(`markRenderFailed:skip-zoid msg=${message.slice(0, 80)}`);
912
+ return;
913
+ }
914
+ setFailed(true);
915
+ forwardError(message);
916
+ };
917
+ setFailed(false);
918
+ const dispatchTokenizedBody = async (body) => {
919
+ const prepared = beforeClickRef.current;
920
+ const effectiveSessionId = prepared?.sessionId ?? sessionId;
921
+ if (onTokenizedBodyRef.current) {
922
+ onTokenizedBodyRef.current(body, {
923
+ sessionId: effectiveSessionId,
924
+ accountPatch: prepared?.accountPatch
925
+ });
926
+ return;
927
+ }
928
+ try {
929
+ const currentSession = sessionRef.current;
930
+ const currentEmail = prepared?.accountPatch?.email ?? emailRef.current;
931
+ const effectiveUserId = prepared?.accountPatch?.userId ?? currentSession?.customer?.id ?? currentSession?.accountData?.userId ?? "";
932
+ const api = new import_js.PaymentAPI(baseUrl);
933
+ const response = await api.processPayment(
934
+ effectiveUserId,
935
+ {
936
+ sessionId: effectiveSessionId,
937
+ tokenizedData: body,
938
+ accountData: {
939
+ userId: effectiveUserId,
940
+ email: currentEmail ?? currentSession?.customer?.email ?? "",
941
+ firstName: prepared?.accountPatch?.firstName ?? currentSession?.customer?.firstName ?? currentSession?.accountData?.firstName ?? "",
942
+ lastName: prepared?.accountPatch?.lastName ?? currentSession?.customer?.lastName ?? currentSession?.accountData?.lastName ?? "",
943
+ country: prepared?.accountPatch?.country ?? currentSession?.customer?.country ?? currentSession?.accountData?.country ?? void 0,
944
+ zip: prepared?.accountPatch?.zip ?? currentSession?.customer?.zip ?? currentSession?.accountData?.zip ?? void 0
945
+ }
946
+ }
947
+ );
948
+ if (response.ok) {
949
+ onCompleteRef.current?.({ status: "succeeded", checkoutMethod: "paypal" });
950
+ return;
951
+ }
952
+ const json = await response.json().catch(() => null);
953
+ const rawMessage = json?.["message"] ?? "PayPal payment failed.";
954
+ const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
955
+ forwardError(message);
956
+ onDeclineRef.current?.(buildDeclineEvent("paypal", message, {
957
+ code: json?.["code"],
958
+ declineCode: json?.["declineCode"]
959
+ }));
960
+ } catch (err) {
961
+ const rawMessage = err instanceof Error ? err.message : "PayPal payment failed.";
962
+ const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
963
+ forwardError(message);
964
+ onDeclineRef.current?.(buildDeclineEvent("paypal", message));
965
+ }
966
+ };
967
+ const createPaypalIntent = async (fallbackMessage) => {
968
+ const prepared = beforeClickRef.current;
969
+ const effectiveSessionId = prepared?.sessionId ?? sessionId;
970
+ const effectiveEmail = prepared?.accountPatch?.email ?? emailRef.current;
971
+ const response = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
972
+ method: "POST",
973
+ headers: { "Content-Type": "application/json" },
974
+ body: JSON.stringify({
975
+ sessionId: effectiveSessionId,
976
+ email: effectiveEmail,
977
+ paymentMethodType: "paypal",
978
+ isPaypal: "true"
979
+ })
980
+ });
981
+ const json = await response.json().catch(() => null);
982
+ if (!response.ok) {
983
+ throw new Error(json?.message ?? fallbackMessage);
984
+ }
985
+ const id = json?.data?.id;
986
+ if (!id) {
987
+ throw new Error(fallbackMessage);
988
+ }
989
+ return id;
990
+ };
991
+ appendDebug("loadScript:scheduled (deferred 1 tick)");
992
+ let loadPromise = null;
993
+ const startTimer = setTimeout(() => {
994
+ if (cancelled) {
995
+ appendDebug("loadScript:skipped (cancelled before defer ran)");
996
+ return;
997
+ }
998
+ appendDebug("loadScript:start");
999
+ const paypalSdkEnv = normalizedEnv === "live" ? "production" : normalizedEnv;
1000
+ loadPromise = (0, import_paypal_js.loadScript)({
1001
+ clientId,
1002
+ currency,
1003
+ // Subscriptions need the `subscription` vault intent; one-time payments
1004
+ // use a standard order capture.
1005
+ intent: isSubscription ? "subscription" : "capture",
1006
+ vault: isSubscription ? true : void 0,
1007
+ // Tell PayPal which environment the clientId belongs to. Without
1008
+ // this, PayPal defaults to live endpoints — and a sandbox clientId
1009
+ // sent to live silently stalls in zoid's prerender forever (no
1010
+ // error, no rejection).
1011
+ ...paypalSdkEnv ? { environment: paypalSdkEnv } : {},
1012
+ // Namespace the sandbox SDK so it can coexist with a production SDK on
1013
+ // the same page without clobbering `window.paypal`.
1014
+ ...paypalSdkEnv === "sandbox" ? { dataNamespace: "paypal_sandbox" } : {}
1015
+ });
1016
+ loadPromise.then((paypal) => {
1017
+ appendDebug(`loadScript:resolved cancelled=${cancelled} ns=${!!paypal} buttons=${!!paypal?.Buttons}`);
1018
+ if (cancelled || !paypal?.Buttons) {
1019
+ if (!cancelled && !paypal?.Buttons) appendDebug("FAIL: namespace missing Buttons factory");
1020
+ return;
1021
+ }
1022
+ const handleApprove = async (data) => {
1023
+ try {
1024
+ setSubmitting(true);
1025
+ onErrorChangeRef.current?.(null);
1026
+ const token = data.subscriptionID ?? data.orderID ?? "";
1027
+ if (!token) {
1028
+ throw new import_shared4.FloPayError(
1029
+ "PayPal did not return an approval token.",
1030
+ "api_error",
1031
+ { code: "paypal_missing_token" }
1032
+ );
1033
+ }
1034
+ await dispatchTokenizedBody({
1035
+ id: token,
1036
+ isPaypal: true
1037
+ });
1038
+ } catch (err) {
1039
+ forwardError(err instanceof Error ? err.message : "PayPal capture failed.");
1040
+ } finally {
1041
+ setSubmitting(false);
1042
+ }
1043
+ };
1044
+ const buttons = paypal.Buttons({
1045
+ style: { layout: "horizontal", height: DEFAULT_BUTTON_HEIGHT, tagline: false },
1046
+ // PayPal's SDK awaits a Promise returned from `onClick` and aborts
1047
+ // the create-order/create-subscription step when `actions.reject()`
1048
+ // is invoked. Run the consumer's `runBeforeButtonClick` here so
1049
+ // inline-session/account patches land before the order is created,
1050
+ // matching the Stripe-rendered PayPal flow.
1051
+ onClick: async (_data, actions) => {
1052
+ const runner = runBeforeButtonClickRef.current;
1053
+ if (runner) {
1054
+ try {
1055
+ const beforeClick = await runner("paypal");
1056
+ if (!beforeClick.proceed) {
1057
+ beforeClickRef.current = null;
1058
+ await actions.reject();
1059
+ return;
1060
+ }
1061
+ beforeClickRef.current = {
1062
+ sessionId: beforeClick.sessionId,
1063
+ accountPatch: beforeClick.accountPatch
1064
+ };
1065
+ } catch (err) {
1066
+ appendDebug(`onClick:runBeforeButtonClick rejected msg=${(err instanceof Error ? err.message : String(err)).slice(0, 120)}`);
1067
+ beforeClickRef.current = null;
1068
+ await actions.reject();
1069
+ return;
1070
+ }
1071
+ } else {
1072
+ beforeClickRef.current = null;
1073
+ }
1074
+ onButtonClickRef.current?.("paypal");
1075
+ await actions.resolve();
1076
+ },
1077
+ // When the SDK is already holding an order/subscription id from a
1078
+ // prior backend round-trip (the `paypal_direct_required` retry
1079
+ // path), feed it straight to PayPal instead of creating a new one.
1080
+ // Otherwise fall back to the normal create-intent call.
1081
+ createOrder: isSubscription ? void 0 : existingOrderId ? () => Promise.resolve(existingOrderId) : () => createPaypalIntent("Failed to create PayPal order."),
1082
+ createSubscription: isSubscription ? existingOrderId ? () => Promise.resolve(existingOrderId) : () => createPaypalIntent("Failed to create PayPal subscription.") : void 0,
1083
+ onApprove: handleApprove,
1084
+ onCancel: () => {
1085
+ beforeClickRef.current = null;
1086
+ onDeclineRef.current?.(buildDeclineEvent("paypal", "PayPal checkout was cancelled."));
1087
+ },
1088
+ onError: (err) => {
1089
+ const message = err instanceof Error ? err.message : "PayPal failed to render.";
1090
+ appendDebug(`onError rendered=${rendered} msg=${message.slice(0, 120)}`);
1091
+ if (rendered) {
1092
+ forwardError(message);
1093
+ onDeclineRef.current?.(buildDeclineEvent("paypal", message));
1094
+ return;
1095
+ }
1096
+ markRenderFailed(message);
1097
+ }
1098
+ });
1099
+ const eligible = buttons.isEligible();
1100
+ appendDebug(`isEligible=${eligible}`);
1101
+ if (!eligible) {
1102
+ setReady(false);
1103
+ markRenderFailed(
1104
+ "PayPal buttons are not eligible to render in this context (paypal_ineligible)."
1105
+ );
1106
+ return;
1107
+ }
1108
+ const typedButtons = buttons;
1109
+ if (debug) {
1110
+ appendDebug(`container:dims ${formatDims(container)} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"}`);
1111
+ }
1112
+ if (debug && typeof MutationObserver !== "undefined") {
1113
+ containerObserver = new MutationObserver((mutations) => {
1114
+ for (const mutation of mutations) {
1115
+ if (mutation.type === "childList") {
1116
+ mutation.addedNodes.forEach((node) => {
1117
+ if (!(node instanceof Element)) return;
1118
+ const tag = node.tagName.toLowerCase();
1119
+ const title = (node.getAttribute("title") ?? "").slice(0, 40);
1120
+ const detail = tag === "iframe" ? ` ${describeIframe(node)}` : "";
1121
+ appendDebug(`child+ ${tag}${title ? ` title="${title}"` : ""}${detail} dims=${formatDims(node)}`);
1122
+ });
1123
+ } else if (mutation.type === "attributes" && mutation.target instanceof Element) {
1124
+ const target = mutation.target;
1125
+ if (target.tagName.toLowerCase() !== "iframe") continue;
1126
+ const attr = mutation.attributeName;
1127
+ if (attr === "src" || attr === "srcdoc") {
1128
+ appendDebug(`attr~ iframe ${attr}=${attr === "srcdoc" ? `[${(target.getAttribute("srcdoc") ?? "").length}ch]` : classifyIframeSrc(target.getAttribute("src"))} dims=${formatDims(target)}`);
1129
+ }
1130
+ }
1131
+ }
1132
+ });
1133
+ containerObserver.observe(container, {
1134
+ childList: true,
1135
+ subtree: true,
1136
+ attributes: true,
1137
+ attributeFilter: ["src", "srcdoc"]
1138
+ });
1139
+ }
1140
+ const snapshotContainer = (when) => {
1141
+ if (cancelled || rendered) return;
1142
+ const iframes = container.querySelectorAll("iframe");
1143
+ const hasStorageAccess = typeof document !== "undefined" && "hasStorageAccess" in document;
1144
+ appendDebug(`watchdog:${when} container=${formatDims(container)} children=${container.childElementCount} iframes=${iframes.length} visibility=${typeof document !== "undefined" ? document.visibilityState : "(no document)"} cookies=${typeof navigator !== "undefined" ? navigator.cookieEnabled : "?"} hasStorageAccessApi=${hasStorageAccess} paypalNetRequests=${paypalRequestCount.value}`);
1145
+ iframes.forEach((frame, i) => {
1146
+ const title = (frame.getAttribute("title") ?? "").slice(0, 40);
1147
+ appendDebug(` iframe[${i}] ${formatDims(frame)}${title ? ` title="${title}"` : ""} ${describeIframe(frame)}`);
1148
+ const content = inspectFrameContent(frame);
1149
+ if (content) appendDebug(` ${content}`);
1150
+ });
1151
+ if (errorMessages.length === 0) {
1152
+ appendDebug(` (no PayPal/zoid window errors captured)`);
1153
+ }
1154
+ };
1155
+ if (debug) {
1156
+ watchdogTimers.push(setTimeout(() => snapshotContainer("3s"), 3e3));
1157
+ watchdogTimers.push(setTimeout(() => snapshotContainer("8s"), 8e3));
1158
+ watchdogTimers.push(setTimeout(() => snapshotContainer("15s"), 15e3));
1159
+ }
1160
+ appendDebug("render:start");
1161
+ buttons.render(container).then(() => {
1162
+ appendDebug(`render:resolved cancelled=${cancelled}`);
1163
+ stopDiagnostics();
1164
+ if (cancelled) {
1165
+ typedButtons.close().catch(() => {
1166
+ });
1167
+ return;
1168
+ }
1169
+ activeButtons = typedButtons;
1170
+ rendered = true;
1171
+ setReady(true);
1172
+ }).catch((err) => {
1173
+ const message = err instanceof Error ? err.message : "PayPal failed to render.";
1174
+ appendDebug(`render:rejected msg=${message.slice(0, 120)}`);
1175
+ stopDiagnostics();
1176
+ markRenderFailed(message);
1177
+ });
1178
+ }).catch((err) => {
1179
+ const message = err instanceof Error ? err.message : "PayPal SDK failed to load.";
1180
+ appendDebug(`loadScript:rejected msg=${message.slice(0, 120)}`);
1181
+ markRenderFailed(message);
1182
+ });
1183
+ }, 0);
1184
+ return () => {
1185
+ cancelled = true;
1186
+ clearTimeout(startTimer);
1187
+ stopDiagnostics();
1188
+ if (activeButtons) {
1189
+ activeButtons.close().catch(() => {
1190
+ });
1191
+ }
1192
+ };
1193
+ }, [baseUrl, clientId, currency, environment, isSubscription, sessionId, existingOrderId]);
1194
+ const debugPanel = debug ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1195
+ "pre",
1196
+ {
1197
+ "data-testid": "flopay-direct-paypal-debug",
1198
+ style: {
1199
+ margin: "0 0 8px 0",
1200
+ padding: "6px 8px",
1201
+ background: failed ? "#fef2f2" : "#f3f4f6",
1202
+ border: `1px solid ${failed ? "#fca5a5" : "#d1d5db"}`,
1203
+ borderRadius: 6,
1204
+ color: "#111827",
1205
+ font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
1206
+ whiteSpace: "pre-wrap",
1207
+ wordBreak: "break-word",
1208
+ maxHeight: 220,
1209
+ overflowY: "auto"
1210
+ },
1211
+ children: [
1212
+ `FloPay/DirectPayPal-debug (ready=${ready} failed=${failed})`,
1213
+ debugLines.length === 0 ? "\n(waiting for first lifecycle event\u2026)" : `
1214
+ ${debugLines.join("\n")}`
1215
+ ]
1216
+ }
1217
+ ) : null;
1218
+ if (failed) {
1219
+ return debug ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: debugPanel }) : null;
1220
+ }
1221
+ return (
1222
+ // Single wrapper so the parent flex container sees exactly one flex item
1223
+ // (otherwise the fragment's placeholder + container become two siblings
1224
+ // and any spacing-sensitive layout has to reason about both). The wrapper
1225
+ // intentionally has no margin/padding so the parent owns all spacing.
1226
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1227
+ debugPanel,
1228
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", minHeight: DEFAULT_BUTTON_HEIGHT }, children: [
1229
+ !ready && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1230
+ "div",
1231
+ {
1232
+ "data-testid": "flopay-direct-paypal-placeholder",
1233
+ style: {
1234
+ position: "absolute",
1235
+ inset: 0,
1236
+ borderRadius: 8,
1237
+ background: "#e5e7eb",
1238
+ animation: "flopay-pulse 1.5s ease-in-out infinite",
1239
+ pointerEvents: "none"
1240
+ }
1241
+ }
1242
+ ),
1243
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1244
+ "div",
1245
+ {
1246
+ ref: containerRef,
1247
+ "data-testid": "flopay-direct-paypal-container",
1248
+ style: {
1249
+ minHeight: DEFAULT_BUTTON_HEIGHT,
1250
+ display: "flex",
1251
+ opacity: ready ? 1 : 0
1252
+ },
1253
+ "aria-busy": submitting || isProcessing
1254
+ }
1255
+ )
1256
+ ] })
1257
+ ] })
1258
+ );
1259
+ }
1260
+
1261
+ // src/split-card-form.tsx
1262
+ var import_shared6 = require("@flopay/shared");
1263
+ var import_jsx_runtime6 = require("react/jsx-runtime");
694
1264
  var WALLET_RESUME_KEY = "flopay_wallet_resume";
695
1265
  var FLOPAY_KEYFRAMES = `
1266
+ .paypal-buttons { margin: 0 !important; vertical-align: top !important; }
696
1267
  @keyframes flopay-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
697
1268
  @keyframes flopay-fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
698
1269
  @keyframes flopay-buttons-enter {
@@ -726,13 +1297,13 @@ function getButtonMethodLabel(method) {
726
1297
  }
727
1298
  }
728
1299
  function normalizeBeforeButtonClickError(method, err) {
729
- return err instanceof import_shared5.FloPayError ? err : new import_shared5.FloPayError(
1300
+ return err instanceof import_shared6.FloPayError ? err : new import_shared6.FloPayError(
730
1301
  err instanceof Error ? err.message : `${getButtonMethodLabel(method)} before-click hook failed.`,
731
1302
  "validation_error"
732
1303
  );
733
1304
  }
734
1305
  function FloPayKeyframes() {
735
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: FLOPAY_KEYFRAMES });
1306
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: FLOPAY_KEYFRAMES });
736
1307
  }
737
1308
  function toCssSize(value) {
738
1309
  if (typeof value === "number") return `${value}px`;
@@ -753,8 +1324,8 @@ function ExpressCheckoutReadySwap({
753
1324
  children
754
1325
  }) {
755
1326
  if (state === "unavailable" || state === "load_error") return null;
756
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
757
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1327
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { position: "relative", minHeight: 44 }, children: [
1328
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
758
1329
  "div",
759
1330
  {
760
1331
  "data-testid": placeholderTestId,
@@ -773,7 +1344,7 @@ function ExpressCheckoutReadySwap({
773
1344
  }
774
1345
  }
775
1346
  ),
776
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1347
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
777
1348
  "div",
778
1349
  {
779
1350
  style: {
@@ -791,9 +1362,9 @@ function ExpressCheckoutReadySwap({
791
1362
  function isExpressCheckoutRowVisible(state) {
792
1363
  return state !== "unavailable" && state !== "load_error";
793
1364
  }
794
- var SplitCardForm = (0, import_react7.forwardRef)(
1365
+ var SplitCardForm = (0, import_react8.forwardRef)(
795
1366
  function SplitCardForm2(props, ref) {
796
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SplitCardFormInner, { ...props, innerRef: ref });
1367
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SplitCardFormInner, { ...props, innerRef: ref });
797
1368
  }
798
1369
  );
799
1370
  function PayPalButtonInner({
@@ -810,15 +1381,15 @@ function PayPalButtonInner({
810
1381
  }) {
811
1382
  const stripe = (0, import_react_stripe_js.useStripe)();
812
1383
  const elements = (0, import_react_stripe_js.useElements)();
813
- const [loadState, setLoadState] = (0, import_react7.useState)("loading");
814
- (0, import_react7.useEffect)(() => {
1384
+ const [loadState, setLoadState] = (0, import_react8.useState)("loading");
1385
+ (0, import_react8.useEffect)(() => {
815
1386
  onLoadStateChange?.(loadState);
816
1387
  }, [loadState, onLoadStateChange]);
817
- const [submitting, setSubmitting] = (0, import_react7.useState)(false);
818
- const paypalResumeAttempted = (0, import_react7.useRef)(false);
819
- const beforeClickRef = (0, import_react7.useRef)(null);
1388
+ const [submitting, setSubmitting] = (0, import_react8.useState)(false);
1389
+ const paypalResumeAttempted = (0, import_react8.useRef)(false);
1390
+ const beforeClickRef = (0, import_react8.useRef)(null);
820
1391
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
821
- (0, import_react7.useEffect)(() => {
1392
+ (0, import_react8.useEffect)(() => {
822
1393
  if (!stripe || paypalResumeAttempted.current) return;
823
1394
  const params = new URLSearchParams(window.location.search);
824
1395
  const paymentIntentId = params.get("payment_intent");
@@ -865,7 +1436,7 @@ function PayPalButtonInner({
865
1436
  }
866
1437
  })();
867
1438
  }, [stripe, onTokenizedBody, onErrorChange, onDecline]);
868
- const handlePayPalClick = (0, import_react7.useCallback)(async (event) => {
1439
+ const handlePayPalClick = (0, import_react8.useCallback)(async (event) => {
869
1440
  if (isProcessing || submitting) {
870
1441
  event.reject();
871
1442
  return;
@@ -883,7 +1454,7 @@ function PayPalButtonInner({
883
1454
  onButtonClick?.("paypal");
884
1455
  event.resolve();
885
1456
  }, [isProcessing, onButtonClick, runBeforeButtonClick, submitting]);
886
- const handlePayPalConfirm = (0, import_react7.useCallback)(async (event) => {
1457
+ const handlePayPalConfirm = (0, import_react8.useCallback)(async (event) => {
887
1458
  if (!stripe || !elements) return;
888
1459
  let prepared = beforeClickRef.current;
889
1460
  beforeClickRef.current = null;
@@ -975,8 +1546,8 @@ function PayPalButtonInner({
975
1546
  setSubmitting(false);
976
1547
  }
977
1548
  }, [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]);
978
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
979
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1549
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1550
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-paypal-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
980
1551
  import_react_stripe_js.ExpressCheckoutElement,
981
1552
  {
982
1553
  onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["paypal"])),
@@ -1001,7 +1572,7 @@ function PayPalButtonInner({
1001
1572
  }
1002
1573
  }
1003
1574
  ) }),
1004
- submitting && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: "processing" })
1575
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
1005
1576
  ] });
1006
1577
  }
1007
1578
  function WalletButtonInner({
@@ -1019,15 +1590,15 @@ function WalletButtonInner({
1019
1590
  }) {
1020
1591
  const stripe = (0, import_react_stripe_js.useStripe)();
1021
1592
  const elements = (0, import_react_stripe_js.useElements)();
1022
- const [loadState, setLoadState] = (0, import_react7.useState)("loading");
1023
- (0, import_react7.useEffect)(() => {
1593
+ const [loadState, setLoadState] = (0, import_react8.useState)("loading");
1594
+ (0, import_react8.useEffect)(() => {
1024
1595
  onLoadStateChange?.(loadState);
1025
1596
  }, [loadState, onLoadStateChange]);
1026
- const [submitting, setSubmitting] = (0, import_react7.useState)(false);
1597
+ const [submitting, setSubmitting] = (0, import_react8.useState)(false);
1027
1598
  const baseUrl = billingApiUrl.replace(/\/+$/, "");
1028
- const lastWalletMethodRef = (0, import_react7.useRef)("card");
1029
- const beforeClickRef = (0, import_react7.useRef)(null);
1030
- const handleWalletConfirm = (0, import_react7.useCallback)(
1599
+ const lastWalletMethodRef = (0, import_react8.useRef)("card");
1600
+ const beforeClickRef = (0, import_react8.useRef)(null);
1601
+ const handleWalletConfirm = (0, import_react8.useCallback)(
1031
1602
  async (event) => {
1032
1603
  if (!stripe || !elements) return;
1033
1604
  const walletType = event.expressPaymentType;
@@ -1116,12 +1687,16 @@ function WalletButtonInner({
1116
1687
  },
1117
1688
  [stripe, elements, sessionId, email, baseUrl, onTokenizedBody, onErrorChange, onDecline, runBeforeButtonClick]
1118
1689
  );
1119
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1120
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1690
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1691
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpressCheckoutReadySwap, { state: loadState, placeholderTestId: "flopay-wallet-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1121
1692
  import_react_stripe_js.ExpressCheckoutElement,
1122
1693
  {
1123
- onReady: (event) => setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"])),
1124
- onLoadError: () => setLoadState("load_error"),
1694
+ onReady: (event) => {
1695
+ setLoadState(resolveExpressCheckoutLoadState(event, ["applePay", "googlePay"]));
1696
+ },
1697
+ onLoadError: (e) => {
1698
+ setLoadState("load_error");
1699
+ },
1125
1700
  onClick: async (event) => {
1126
1701
  lastWalletMethodRef.current = event.expressPaymentType === "apple_pay" ? "apple_pay" : "google_pay";
1127
1702
  const beforeClick = runBeforeButtonClick ? await runBeforeButtonClick(lastWalletMethodRef.current) : { proceed: true };
@@ -1156,7 +1731,7 @@ function WalletButtonInner({
1156
1731
  }
1157
1732
  }
1158
1733
  ) }),
1159
- submitting && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: "processing" })
1734
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: "processing" })
1160
1735
  ] });
1161
1736
  }
1162
1737
  function SplitCardFormInner({
@@ -1208,55 +1783,64 @@ function SplitCardFormInner({
1208
1783
  totalAmount = 0,
1209
1784
  currency = "usd",
1210
1785
  initialCardOpen = false,
1786
+ directPaypal,
1787
+ isSubscription = false,
1788
+ session,
1789
+ debug = false,
1211
1790
  innerRef
1212
1791
  }) {
1213
1792
  const flopay = useFloPay();
1214
1793
  const paypalFlopay = usePayPalFloPay();
1215
1794
  const elements = useElements();
1216
- const checkout = (0, import_react7.useContext)(CheckoutContext);
1795
+ const checkout = (0, import_react8.useContext)(CheckoutContext);
1217
1796
  const contextBillingUrl = useBillingApiUrl();
1218
- const [processing, setProcessing] = (0, import_react7.useState)(false);
1219
- const [error, setError] = (0, import_react7.useState)(null);
1220
- const [is3DSActive, setIs3DSActive] = (0, import_react7.useState)(false);
1221
- const [selectedCountry, setSelectedCountry] = (0, import_react7.useState)(countryProp ?? "US");
1222
- const [zipCode, setZipCode] = (0, import_react7.useState)(zipProp ?? "");
1223
- const [addressLine1, setAddressLine1] = (0, import_react7.useState)(addressLine1Prop ?? "");
1224
- const [addressLine2, setAddressLine2] = (0, import_react7.useState)(addressLine2Prop ?? "");
1225
- const [city, setCity] = (0, import_react7.useState)(cityProp ?? "");
1226
- const [stateValue, setStateValue] = (0, import_react7.useState)(stateProp ?? "");
1227
- const [accountPatch, setAccountPatch] = (0, import_react7.useState)({});
1228
- const zipCodeRef = (0, import_react7.useRef)(zipProp ?? "");
1229
- const selectedCountryRef = (0, import_react7.useRef)(countryProp ?? "US");
1230
- const addressLine1Ref = (0, import_react7.useRef)(addressLine1Prop ?? "");
1231
- const addressLine2Ref = (0, import_react7.useRef)(addressLine2Prop ?? "");
1232
- const cityRef = (0, import_react7.useRef)(cityProp ?? "");
1233
- const stateRef = (0, import_react7.useRef)(stateProp ?? "");
1234
- const avsConfig = (0, import_react7.useMemo)(() => (0, import_shared4.resolveAVSConfig)(enableAVSProp), [enableAVSProp]);
1797
+ const [processing, setProcessing] = (0, import_react8.useState)(false);
1798
+ const [error, setError] = (0, import_react8.useState)(null);
1799
+ const [is3DSActive, setIs3DSActive] = (0, import_react8.useState)(false);
1800
+ const [selectedCountry, setSelectedCountry] = (0, import_react8.useState)(countryProp ?? "US");
1801
+ const [zipCode, setZipCode] = (0, import_react8.useState)(zipProp ?? "");
1802
+ const [addressLine1, setAddressLine1] = (0, import_react8.useState)(addressLine1Prop ?? "");
1803
+ const [addressLine2, setAddressLine2] = (0, import_react8.useState)(addressLine2Prop ?? "");
1804
+ const [city, setCity] = (0, import_react8.useState)(cityProp ?? "");
1805
+ const [stateValue, setStateValue] = (0, import_react8.useState)(stateProp ?? "");
1806
+ const [accountPatch, setAccountPatch] = (0, import_react8.useState)({});
1807
+ const zipCodeRef = (0, import_react8.useRef)(zipProp ?? "");
1808
+ const selectedCountryRef = (0, import_react8.useRef)(countryProp ?? "US");
1809
+ const addressLine1Ref = (0, import_react8.useRef)(addressLine1Prop ?? "");
1810
+ const addressLine2Ref = (0, import_react8.useRef)(addressLine2Prop ?? "");
1811
+ const cityRef = (0, import_react8.useRef)(cityProp ?? "");
1812
+ const stateRef = (0, import_react8.useRef)(stateProp ?? "");
1813
+ const avsConfig = (0, import_react8.useMemo)(() => (0, import_shared5.resolveAVSConfig)(enableAVSProp), [enableAVSProp]);
1235
1814
  const enableAVS = avsConfig !== null;
1236
- const [viewState, setViewState] = (0, import_react7.useState)(initialCardOpen ? "card" : "buttons");
1815
+ const [viewState, setViewState] = (0, import_react8.useState)(initialCardOpen ? "card" : "buttons");
1237
1816
  const showCardForm = viewState === "expanding" || viewState === "card";
1238
1817
  const TRANSITION_MS = 280;
1239
- const expandToCard = (0, import_react7.useCallback)(() => {
1818
+ const expandToCard = (0, import_react8.useCallback)(() => {
1240
1819
  setViewState("expanding");
1241
1820
  setTimeout(() => setViewState("card"), TRANSITION_MS);
1242
1821
  }, []);
1243
- const collapseToButtons = (0, import_react7.useCallback)(() => {
1822
+ const collapseToButtons = (0, import_react8.useCallback)(() => {
1244
1823
  setViewState("collapsing");
1245
1824
  setTimeout(() => setViewState("buttons"), TRANSITION_MS);
1246
1825
  }, []);
1247
- (0, import_react7.useEffect)(() => {
1826
+ (0, import_react8.useEffect)(() => {
1248
1827
  if (layout === "buttons" && initialCardOpen) {
1249
1828
  setViewState("card");
1250
1829
  }
1251
1830
  }, [layout, initialCardOpen]);
1252
- const [fullName, setFullName] = (0, import_react7.useState)("");
1253
- const [formReady, setFormReady] = (0, import_react7.useState)(false);
1254
- const [overlayStatus, setOverlayStatus] = (0, import_react7.useState)(null);
1255
- const processingRef = (0, import_react7.useRef)(false);
1831
+ const [fullName, setFullName] = (0, import_react8.useState)("");
1832
+ const [formReady, setFormReady] = (0, import_react8.useState)(false);
1833
+ const [overlayStatus, setOverlayStatus] = (0, import_react8.useState)(null);
1834
+ const processingRef = (0, import_react8.useRef)(false);
1835
+ const [paypalDirectRetry, setPaypalDirectRetry] = (0, import_react8.useState)(null);
1836
+ const paypalDirectRetryRef = (0, import_react8.useRef)(paypalDirectRetry);
1837
+ (0, import_react8.useEffect)(() => {
1838
+ paypalDirectRetryRef.current = paypalDirectRetry;
1839
+ }, [paypalDirectRetry]);
1256
1840
  const resolvedBillingApiUrl = billingApiUrl || contextBillingUrl;
1257
1841
  const displayError = externalError ?? error;
1258
- const bStyles = (0, import_react7.useMemo)(() => {
1259
- const base = (0, import_shared4.resolveButtonsLayoutTheme)(buttonsTheme);
1842
+ const bStyles = (0, import_react8.useMemo)(() => {
1843
+ const base = (0, import_shared5.resolveButtonsLayoutTheme)(buttonsTheme);
1260
1844
  if (!buttonsStylesOverride) return base;
1261
1845
  return {
1262
1846
  ...base,
@@ -1273,7 +1857,7 @@ function SplitCardFormInner({
1273
1857
  const isSubmitting = (externalProcessing ?? processing) || isInlineSessionPatchProcessing;
1274
1858
  const isSelfContained = !onTokenizedBody;
1275
1859
  const baseUrl = resolvedBillingApiUrl.replace(/\/+$/, "");
1276
- const resolvedAccount = (0, import_react7.useMemo)(() => mergeAccountPatch({
1860
+ const resolvedAccount = (0, import_react8.useMemo)(() => mergeAccountPatch({
1277
1861
  userId,
1278
1862
  email,
1279
1863
  firstName,
@@ -1281,63 +1865,66 @@ function SplitCardFormInner({
1281
1865
  country: countryProp,
1282
1866
  zip: zipProp
1283
1867
  }, accountPatch), [userId, email, firstName, lastName, countryProp, zipProp, accountPatch]);
1284
- const stripeInstance = (0, import_react7.useMemo)(() => {
1868
+ const stripeInstance = (0, import_react8.useMemo)(() => {
1285
1869
  if (!flopay) return null;
1286
1870
  return flopay.getRawProvider();
1287
1871
  }, [flopay]);
1288
- const paypalStripeInstance = (0, import_react7.useMemo)(() => {
1872
+ const paypalStripeInstance = (0, import_react8.useMemo)(() => {
1289
1873
  if (!paypalFlopay) return null;
1290
1874
  return paypalFlopay.getRawProvider();
1291
1875
  }, [paypalFlopay]);
1292
1876
  const amountInCents = totalAmount || 100;
1293
- const walletOptions = (0, import_react7.useMemo)(() => ({
1877
+ const walletOptions = (0, import_react8.useMemo)(() => ({
1294
1878
  mode: "payment",
1295
1879
  amount: amountInCents,
1296
1880
  currency: currency.toLowerCase(),
1297
1881
  paymentMethodCreation: "manual",
1298
1882
  captureMethod: "manual"
1299
1883
  }), [amountInCents, currency]);
1300
- const paypalOptions = (0, import_react7.useMemo)(() => ({
1884
+ const paypalOptions = (0, import_react8.useMemo)(() => ({
1301
1885
  mode: "payment",
1302
1886
  amount: amountInCents,
1303
1887
  currency: currency.toLowerCase(),
1304
1888
  captureMethod: "manual",
1305
1889
  setupFutureUsage: "off_session"
1306
1890
  }), [amountInCents, currency]);
1307
- const updateError = (0, import_react7.useCallback)(
1891
+ const updateError = (0, import_react8.useCallback)(
1308
1892
  (err) => {
1309
1893
  setError(err);
1310
1894
  onErrorChange?.(err);
1311
1895
  },
1312
1896
  [onErrorChange]
1313
1897
  );
1314
- const emitDecline = (0, import_react7.useCallback)(
1898
+ const emitDecline = (0, import_react8.useCallback)(
1315
1899
  (method, input, overrides) => {
1316
1900
  onDecline?.(buildDeclineEvent(method, input, overrides));
1317
1901
  },
1318
1902
  [onDecline]
1319
1903
  );
1320
1904
  const showWallets = showApplePay || showGooglePay;
1321
- const [paypalLoadState, setPaypalLoadState] = (0, import_react7.useState)("loading");
1322
- const [walletLoadState, setWalletLoadState] = (0, import_react7.useState)("loading");
1323
- const [inAppBrowserDetected, setInAppBrowserDetected] = (0, import_react7.useState)();
1324
- (0, import_react7.useEffect)(() => {
1905
+ const [paypalLoadState, setPaypalLoadState] = (0, import_react8.useState)("loading");
1906
+ const [walletLoadState, setWalletLoadState] = (0, import_react8.useState)("loading");
1907
+ const [directPaypalReady, setDirectPaypalReady] = (0, import_react8.useState)(false);
1908
+ const [inAppBrowserDetected, setInAppBrowserDetected] = (0, import_react8.useState)();
1909
+ (0, import_react8.useEffect)(() => {
1325
1910
  setInAppBrowserDetected(isInAppBrowser());
1326
1911
  }, []);
1327
- const shouldShowPayPal = showPayPal && inAppBrowserDetected === false;
1328
- const shouldShowWallets = showWallets && inAppBrowserDetected === false;
1329
- const shouldRenderPayPal = shouldShowPayPal && !!paypalStripeInstance;
1912
+ const directPaypalConfigured = !!directPaypal?.clientId;
1913
+ const shouldShowPayPal = showPayPal && (directPaypalConfigured || inAppBrowserDetected === false);
1914
+ const shouldShowWallets = showWallets;
1915
+ const shouldRenderDirectPayPal = shouldShowPayPal && directPaypalConfigured;
1916
+ const shouldRenderStripePayPal = shouldShowPayPal && !directPaypalConfigured && !!paypalStripeInstance;
1330
1917
  const shouldRenderWallets = shouldShowWallets && !!stripeInstance;
1331
- const shouldDisplayPayPalRow = shouldRenderPayPal && isExpressCheckoutRowVisible(paypalLoadState);
1918
+ const shouldDisplayPayPalRow = shouldRenderDirectPayPal ? directPaypalReady : shouldRenderStripePayPal && isExpressCheckoutRowVisible(paypalLoadState);
1332
1919
  const shouldDisplayWalletRow = shouldRenderWallets && isExpressCheckoutRowVisible(walletLoadState);
1333
- const handleNameChange = (0, import_react7.useCallback)((value) => {
1920
+ const handleNameChange = (0, import_react8.useCallback)((value) => {
1334
1921
  setFullName(value);
1335
1922
  onFullNameChange?.(value);
1336
1923
  const parts = value.trim().split(/\s+/);
1337
1924
  onFirstNameChange?.(parts[0] ?? "");
1338
1925
  onLastNameChange?.(parts.length > 1 ? parts.slice(1).join(" ") : "");
1339
1926
  }, [onFullNameChange, onFirstNameChange, onLastNameChange]);
1340
- const applyInlineSessionPatch = (0, import_react7.useCallback)(
1927
+ const applyInlineSessionPatch = (0, import_react8.useCallback)(
1341
1928
  (patch, method) => {
1342
1929
  if (!checkout.applyInlineSessionPatch) {
1343
1930
  return Promise.resolve({ error: null, sessionId });
@@ -1354,7 +1941,7 @@ function SplitCardFormInner({
1354
1941
  },
1355
1942
  [checkout.applyInlineSessionPatch, onError, sessionId, updateError]
1356
1943
  );
1357
- const runBeforeButtonClick = (0, import_react7.useCallback)(async (method) => {
1944
+ const runBeforeButtonClick = (0, import_react8.useCallback)(async (method) => {
1358
1945
  if (!onBeforeButtonClick) return { proceed: true };
1359
1946
  try {
1360
1947
  const result = await onBeforeButtonClick({
@@ -1390,7 +1977,7 @@ function SplitCardFormInner({
1390
1977
  return { proceed: false };
1391
1978
  }
1392
1979
  }, [applyInlineSessionPatch, checkout.inlineSessionDraft, onBeforeButtonClick, onError, sessionId, updateError]);
1393
- const processPaymentInternal = (0, import_react7.useCallback)(
1980
+ const processPaymentInternal = (0, import_react8.useCallback)(
1394
1981
  async (tokenizedBody, overrides) => {
1395
1982
  if (processingRef.current) return;
1396
1983
  processingRef.current = true;
@@ -1402,7 +1989,7 @@ function SplitCardFormInner({
1402
1989
  const resolvedCompletionPaymentMethodId = overrides?.completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
1403
1990
  const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
1404
1991
  try {
1405
- const api = new import_js.PaymentAPI(baseUrl);
1992
+ const api = new import_js2.PaymentAPI(baseUrl);
1406
1993
  const response = await api.processPayment(effectiveAccount.userId ?? "", {
1407
1994
  sessionId: effectiveSessionId,
1408
1995
  tokenizedData: requestTokenizedBody,
@@ -1413,18 +2000,18 @@ function SplitCardFormInner({
1413
2000
  lastName: effectiveAccount.lastName ?? fullName.trim().split(/\s+/).slice(1).join(" ") ?? "",
1414
2001
  ...avsConfig ? (() => {
1415
2002
  const c = selectedCountryRef.current;
1416
- const stateVisible = (0, import_shared4.isAVSFieldVisible)(avsConfig.state, c);
1417
- const line1Visible = (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, c);
1418
- const zipVisible = (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, c);
1419
- const derivedState = line1Visible && !stateVisible && zipVisible ? (0, import_shared4.getStateFromPostalCode)(c, zipCodeRef.current ?? "") : null;
2003
+ const stateVisible = (0, import_shared5.isAVSFieldVisible)(avsConfig.state, c);
2004
+ const line1Visible = (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, c);
2005
+ const zipVisible = (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, c);
2006
+ const derivedState = line1Visible && !stateVisible && zipVisible ? (0, import_shared5.getStateFromPostalCode)(c, zipCodeRef.current ?? "") : null;
1420
2007
  const stateValue2 = stateVisible ? stateRef.current : derivedState;
1421
2008
  return {
1422
2009
  country: c,
1423
2010
  ...zipVisible && zipCodeRef.current ? { zip: zipCodeRef.current } : {},
1424
- ...(0, import_shared4.isAVSFieldVisible)(avsConfig.city, c) && cityRef.current ? { city: cityRef.current } : {},
2011
+ ...(0, import_shared5.isAVSFieldVisible)(avsConfig.city, c) && cityRef.current ? { city: cityRef.current } : {},
1425
2012
  ...stateValue2 ? { state: stateValue2 } : {},
1426
2013
  ...line1Visible && addressLine1Ref.current ? { addressLine1: addressLine1Ref.current } : {},
1427
- ...(0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_2, c) && addressLine2Ref.current ? { addressLine2: addressLine2Ref.current } : {}
2014
+ ...(0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, c) && addressLine2Ref.current ? { addressLine2: addressLine2Ref.current } : {}
1428
2015
  };
1429
2016
  })() : {}
1430
2017
  },
@@ -1436,17 +2023,18 @@ function SplitCardFormInner({
1436
2023
  // Resolved exposure: which fields were actually shown for the active country.
1437
2024
  // Country-scoped rules (e.g. ['US', 'CA']) are flattened to booleans here.
1438
2025
  avsConfig: avsConfig ? {
1439
- country: (0, import_shared4.isAVSFieldVisible)(avsConfig.country, selectedCountryRef.current),
1440
- postal_code: (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, selectedCountryRef.current),
1441
- address_line_1: (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, selectedCountryRef.current),
1442
- address_line_2: (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_2, selectedCountryRef.current),
1443
- city: (0, import_shared4.isAVSFieldVisible)(avsConfig.city, selectedCountryRef.current),
1444
- state: (0, import_shared4.isAVSFieldVisible)(avsConfig.state, selectedCountryRef.current)
2026
+ country: (0, import_shared5.isAVSFieldVisible)(avsConfig.country, selectedCountryRef.current),
2027
+ postal_code: (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, selectedCountryRef.current),
2028
+ address_line_1: (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, selectedCountryRef.current),
2029
+ address_line_2: (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, selectedCountryRef.current),
2030
+ city: (0, import_shared5.isAVSFieldVisible)(avsConfig.city, selectedCountryRef.current),
2031
+ state: (0, import_shared5.isAVSFieldVisible)(avsConfig.state, selectedCountryRef.current)
1445
2032
  } : void 0
1446
2033
  });
1447
2034
  if (response.ok) {
1448
2035
  markSessionRecentlyCompleted(effectiveSessionId);
1449
2036
  setOverlayStatus("success");
2037
+ setPaypalDirectRetry(null);
1450
2038
  await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_SUCCESS_DELAY_MS));
1451
2039
  onComplete?.({
1452
2040
  status: "succeeded",
@@ -1470,18 +2058,18 @@ function SplitCardFormInner({
1470
2058
  const retryCC = selectedCountryRef.current;
1471
2059
  const retryCountry = enableAVS ? retryCC : effectiveAccount.country;
1472
2060
  if (retryCountry) retryBillingAddress["country"] = retryCountry;
1473
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, retryCC) && zipCodeRef.current.trim()) {
2061
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, retryCC) && zipCodeRef.current.trim()) {
1474
2062
  retryBillingAddress["postal_code"] = zipCodeRef.current.trim();
1475
2063
  } else if (!avsConfig && effectiveAccount.zip) {
1476
2064
  retryBillingAddress["postal_code"] = effectiveAccount.zip;
1477
2065
  }
1478
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && addressLine1Ref.current.trim()) retryBillingAddress["line1"] = addressLine1Ref.current.trim();
1479
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_2, retryCC) && addressLine2Ref.current.trim()) retryBillingAddress["line2"] = addressLine2Ref.current.trim();
1480
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.city, retryCC) && cityRef.current.trim()) retryBillingAddress["city"] = cityRef.current.trim();
1481
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.state, retryCC) && stateRef.current.trim()) {
2066
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && addressLine1Ref.current.trim()) retryBillingAddress["line1"] = addressLine1Ref.current.trim();
2067
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, retryCC) && addressLine2Ref.current.trim()) retryBillingAddress["line2"] = addressLine2Ref.current.trim();
2068
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.city, retryCC) && cityRef.current.trim()) retryBillingAddress["city"] = cityRef.current.trim();
2069
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.state, retryCC) && stateRef.current.trim()) {
1482
2070
  retryBillingAddress["state"] = stateRef.current.trim();
1483
- } else if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && !(0, import_shared4.isAVSFieldVisible)(avsConfig.state, retryCC) && (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, retryCC)) {
1484
- const derivedRetryState = (0, import_shared4.getStateFromPostalCode)(retryCC, zipCodeRef.current.trim());
2071
+ } else if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, retryCC) && !(0, import_shared5.isAVSFieldVisible)(avsConfig.state, retryCC) && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, retryCC)) {
2072
+ const derivedRetryState = (0, import_shared5.getStateFromPostalCode)(retryCC, zipCodeRef.current.trim());
1485
2073
  if (derivedRetryState) retryBillingAddress["state"] = derivedRetryState;
1486
2074
  }
1487
2075
  const result = await flopay.confirmPayment({
@@ -1554,6 +2142,24 @@ function SplitCardFormInner({
1554
2142
  }
1555
2143
  return;
1556
2144
  }
2145
+ if (json?.type === "paypal_direct_required") {
2146
+ const orderId = json["orderId"];
2147
+ if (!orderId) {
2148
+ setOverlayStatus("error");
2149
+ updateError("PayPal retry required but no order id provided.");
2150
+ return;
2151
+ }
2152
+ const prevAttempts = paypalDirectRetryRef.current?.attempts ?? 0;
2153
+ if (prevAttempts >= 2) {
2154
+ setOverlayStatus("error");
2155
+ updateError("PayPal payment could not be completed after multiple attempts.");
2156
+ emitDecline("paypal", "paypal_direct_required retry limit exceeded");
2157
+ return;
2158
+ }
2159
+ setPaypalDirectRetry({ orderId, attempts: prevAttempts + 1 });
2160
+ setOverlayStatus(null);
2161
+ return;
2162
+ }
1557
2163
  setOverlayStatus("error");
1558
2164
  const message = json?.message ?? "Payment failed. Please try again.";
1559
2165
  updateError(message);
@@ -1574,7 +2180,7 @@ function SplitCardFormInner({
1574
2180
  },
1575
2181
  [baseUrl, sessionId, resolvedAccount, fullName, chv, flopay, paypalFlopay, onComplete, onError, updateError, emitDecline]
1576
2182
  );
1577
- const dispatchTokenizedBody = (0, import_react7.useCallback)(
2183
+ const dispatchTokenizedBody = (0, import_react8.useCallback)(
1578
2184
  (tokenizedBody, overrides) => {
1579
2185
  if (onTokenizedBody) {
1580
2186
  onTokenizedBody(tokenizedBody);
@@ -1584,7 +2190,7 @@ function SplitCardFormInner({
1584
2190
  },
1585
2191
  [onTokenizedBody, processPaymentInternal]
1586
2192
  );
1587
- (0, import_react7.useImperativeHandle)(innerRef, () => ({
2193
+ (0, import_react8.useImperativeHandle)(innerRef, () => ({
1588
2194
  async handleNextAction(secret) {
1589
2195
  if (!flopay) return;
1590
2196
  setIs3DSActive(true);
@@ -1611,7 +2217,7 @@ function SplitCardFormInner({
1611
2217
  }
1612
2218
  }
1613
2219
  }), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
1614
- (0, import_react7.useEffect)(() => {
2220
+ (0, import_react8.useEffect)(() => {
1615
2221
  if (typeof window === "undefined") return;
1616
2222
  const stored = localStorage.getItem(WALLET_RESUME_KEY);
1617
2223
  if (!stored) return;
@@ -1629,7 +2235,7 @@ function SplitCardFormInner({
1629
2235
  localStorage.removeItem(WALLET_RESUME_KEY);
1630
2236
  }
1631
2237
  }, [sessionId, dispatchTokenizedBody]);
1632
- const handleSubmit = (0, import_react7.useCallback)(
2238
+ const handleSubmit = (0, import_react8.useCallback)(
1633
2239
  async (e) => {
1634
2240
  e.preventDefault();
1635
2241
  if (!flopay || !elements || isSubmitting || processingRef.current) return;
@@ -1643,20 +2249,20 @@ function SplitCardFormInner({
1643
2249
  try {
1644
2250
  if (avsConfig) {
1645
2251
  const country = selectedCountryRef.current;
1646
- if ((0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, country) && !zipCodeRef.current.trim()) {
1647
- updateError((0, import_shared4.getPostalCodeLabel)(country) + " is required");
2252
+ if ((0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, country) && !zipCodeRef.current.trim()) {
2253
+ updateError((0, import_shared5.getPostalCodeLabel)(country) + " is required");
1648
2254
  return;
1649
2255
  }
1650
- if ((0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, country) && !addressLine1Ref.current.trim()) {
2256
+ if ((0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, country) && !addressLine1Ref.current.trim()) {
1651
2257
  updateError("Street address is required");
1652
2258
  return;
1653
2259
  }
1654
- if ((0, import_shared4.isAVSFieldVisible)(avsConfig.city, country) && !cityRef.current.trim()) {
2260
+ if ((0, import_shared5.isAVSFieldVisible)(avsConfig.city, country) && !cityRef.current.trim()) {
1655
2261
  updateError("City is required");
1656
2262
  return;
1657
2263
  }
1658
- if ((0, import_shared4.isAVSFieldVisible)(avsConfig.state, country) && !stateRef.current.trim()) {
1659
- updateError((0, import_shared4.getStateLabel)(country) + " is required");
2264
+ if ((0, import_shared5.isAVSFieldVisible)(avsConfig.state, country) && !stateRef.current.trim()) {
2265
+ updateError((0, import_shared5.getStateLabel)(country) + " is required");
1660
2266
  return;
1661
2267
  }
1662
2268
  }
@@ -1670,18 +2276,18 @@ function SplitCardFormInner({
1670
2276
  const cc = selectedCountryRef.current;
1671
2277
  const avsCountry = enableAVS ? cc : resolvedAccount.country;
1672
2278
  if (avsCountry) billingAddress["country"] = avsCountry;
1673
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, cc) && zipCodeRef.current.trim()) {
2279
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) && zipCodeRef.current.trim()) {
1674
2280
  billingAddress["postal_code"] = zipCodeRef.current.trim();
1675
2281
  } else if (!avsConfig && resolvedAccount.zip) {
1676
2282
  billingAddress["postal_code"] = resolvedAccount.zip;
1677
2283
  }
1678
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, cc) && addressLine1Ref.current.trim()) billingAddress["line1"] = addressLine1Ref.current.trim();
1679
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_2, cc) && addressLine2Ref.current.trim()) billingAddress["line2"] = addressLine2Ref.current.trim();
1680
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.city, cc) && cityRef.current.trim()) billingAddress["city"] = cityRef.current.trim();
1681
- if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.state, cc) && stateRef.current.trim()) {
2284
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && addressLine1Ref.current.trim()) billingAddress["line1"] = addressLine1Ref.current.trim();
2285
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, cc) && addressLine2Ref.current.trim()) billingAddress["line2"] = addressLine2Ref.current.trim();
2286
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && cityRef.current.trim()) billingAddress["city"] = cityRef.current.trim();
2287
+ if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && stateRef.current.trim()) {
1682
2288
  billingAddress["state"] = stateRef.current.trim();
1683
- } else if (avsConfig && (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, cc) && !(0, import_shared4.isAVSFieldVisible)(avsConfig.state, cc) && (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, cc)) {
1684
- const derivedSubmitState = (0, import_shared4.getStateFromPostalCode)(cc, zipCodeRef.current.trim());
2289
+ } else if (avsConfig && (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && !(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc)) {
2290
+ const derivedSubmitState = (0, import_shared5.getStateFromPostalCode)(cc, zipCodeRef.current.trim());
1685
2291
  if (derivedSubmitState) billingAddress["state"] = derivedSubmitState;
1686
2292
  }
1687
2293
  const billingDetails = {
@@ -1695,7 +2301,7 @@ function SplitCardFormInner({
1695
2301
  return;
1696
2302
  }
1697
2303
  if (!sessionId || !resolvedAccount.email) {
1698
- throw new import_shared5.FloPayError("Missing sessionId or email", "validation_error");
2304
+ throw new import_shared6.FloPayError("Missing sessionId or email", "validation_error");
1699
2305
  }
1700
2306
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
1701
2307
  method: "POST",
@@ -1721,7 +2327,7 @@ function SplitCardFormInner({
1721
2327
  }
1722
2328
  const intentJson = await intentResponse.json();
1723
2329
  const intentClientSecret = intentJson.data?.id;
1724
- if (!intentClientSecret) throw new import_shared5.FloPayError("No client_secret in payment intent response", "api_error");
2330
+ if (!intentClientSecret) throw new import_shared6.FloPayError("No client_secret in payment intent response", "api_error");
1725
2331
  const confirmResult = await flopay.confirmCardPayment({
1726
2332
  clientSecret: intentClientSecret,
1727
2333
  paymentMethodId: pmResult.paymentMethodId
@@ -1742,7 +2348,7 @@ function SplitCardFormInner({
1742
2348
  const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
1743
2349
  const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
1744
2350
  if (!paymentIntentId) {
1745
- const error2 = new import_shared5.FloPayError("No payment intent returned after confirmation.", "api_error");
2351
+ const error2 = new import_shared6.FloPayError("No payment intent returned after confirmation.", "api_error");
1746
2352
  setOverlayStatus("error");
1747
2353
  updateError(error2.message);
1748
2354
  onError?.(error2);
@@ -1771,7 +2377,7 @@ function SplitCardFormInner({
1771
2377
  );
1772
2378
  const isReady = flopay !== null && elements !== null;
1773
2379
  if (!isReady) {
1774
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
2380
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." });
1775
2381
  }
1776
2382
  const isButtons = layout === "buttons";
1777
2383
  const resolvedBorder = isButtons ? bStyles.cardInputBorder ?? "#e5e7eb" : "#A4A4FF";
@@ -1814,7 +2420,7 @@ function SplitCardFormInner({
1814
2420
  invalid: { color: "#ef4444" }
1815
2421
  }
1816
2422
  };
1817
- const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
2423
+ const cardFormBlock = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
1818
2424
  backgroundColor: cardBg,
1819
2425
  borderRadius: "8px",
1820
2426
  padding: isButtons ? "0" : "1rem",
@@ -1822,7 +2428,7 @@ function SplitCardFormInner({
1822
2428
  ...isButtons ? { padding: bStyles.cardFormContainer?.padding ?? "0" } : {},
1823
2429
  ...sharedInputPlaceholderVars
1824
2430
  }, children: [
1825
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `
2431
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
1826
2432
  .flopay-shared-input::placeholder {
1827
2433
  color: var(--flopay-input-placeholder-color);
1828
2434
  opacity: 1;
@@ -1831,12 +2437,12 @@ function SplitCardFormInner({
1831
2437
  font-weight: var(--flopay-input-font-weight);
1832
2438
  }
1833
2439
  ` }),
1834
- isButtons && showCardForm && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
2440
+ isButtons && showCardForm && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
1835
2441
  display: "flex",
1836
2442
  alignItems: "center",
1837
2443
  padding: "0.75rem 0 0.625rem"
1838
2444
  }, children: [
1839
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2445
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1840
2446
  "button",
1841
2447
  {
1842
2448
  type: "button",
@@ -1858,7 +2464,7 @@ function SplitCardFormInner({
1858
2464
  },
1859
2465
  "aria-label": "Back to payment methods",
1860
2466
  children: [
1861
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: {
2467
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
1862
2468
  display: "inline-flex",
1863
2469
  alignItems: "center",
1864
2470
  justifyContent: "center",
@@ -1868,12 +2474,12 @@ function SplitCardFormInner({
1868
2474
  backgroundColor: "#f3f4f6",
1869
2475
  transition: "background-color 0.15s",
1870
2476
  ...bStyles.backButtonIcon
1871
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
1872
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
2477
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
2478
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
1873
2479
  ]
1874
2480
  }
1875
2481
  ),
1876
- hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2482
+ hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
1877
2483
  flex: 1,
1878
2484
  textAlign: "center",
1879
2485
  fontWeight: 600,
@@ -1881,18 +2487,18 @@ function SplitCardFormInner({
1881
2487
  color: "#262833",
1882
2488
  paddingRight: 80,
1883
2489
  ...bStyles.title
1884
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TitleContentSlot, { content: cardTitleContent }) })
2490
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
1885
2491
  ] }),
1886
- !isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
1887
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2492
+ !isButtons && !hideTitle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { textAlign: "center", fontWeight: 600, fontSize: "1.1rem", padding: "0.5rem 0", color: "#262833" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) }),
2493
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
1888
2494
  backgroundColor: cardInputBg,
1889
2495
  border: `1px solid ${resolvedBorder}`,
1890
2496
  borderTopLeftRadius: "8px",
1891
2497
  borderTopRightRadius: "8px",
1892
2498
  padding: "10px"
1893
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
1894
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex" }, children: [
1895
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2499
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardNumberElement, { onReady: () => setFormReady(true), options: stripeElementStyle }) }),
2500
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex" }, children: [
2501
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
1896
2502
  flex: 1,
1897
2503
  backgroundColor: cardInputBg,
1898
2504
  border: `1px solid ${resolvedBorder}`,
@@ -1900,23 +2506,23 @@ function SplitCardFormInner({
1900
2506
  borderRight: "none",
1901
2507
  borderBottomLeftRadius: "8px",
1902
2508
  padding: "10px"
1903
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
1904
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2509
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardExpiryElement, { options: stripeElementStyle }) }),
2510
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
1905
2511
  flex: 1,
1906
2512
  backgroundColor: cardInputBg,
1907
2513
  border: `1px solid ${resolvedBorder}`,
1908
2514
  borderTop: "none",
1909
2515
  borderBottomRightRadius: "8px",
1910
2516
  padding: "10px"
1911
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardCvcElement, { options: stripeElementStyle }) })
2517
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardCvcElement, { options: stripeElementStyle }) })
1912
2518
  ] }),
1913
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2519
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
1914
2520
  backgroundColor: cardInputBg,
1915
2521
  border: `1px solid ${resolvedBorder}`,
1916
2522
  borderRadius: "8px",
1917
2523
  marginTop: "0.5rem",
1918
2524
  padding: "10px"
1919
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2525
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1920
2526
  "input",
1921
2527
  {
1922
2528
  className: "flopay-shared-input",
@@ -1954,9 +2560,9 @@ function SplitCardFormInner({
1954
2560
  ...sharedInputTypography,
1955
2561
  ...isButtons && bStyles.nameInput ? bStyles.nameInput : {}
1956
2562
  });
1957
- const stateOpts = (0, import_shared4.getStateOptions)(cc);
1958
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1959
- (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_1, cc) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: inputWrapStyle(bStyles.addressLine1Input), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2563
+ const stateOpts = (0, import_shared5.getStateOptions)(cc);
2564
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2565
+ (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_1, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: inputWrapStyle(bStyles.addressLine1Input), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1960
2566
  "input",
1961
2567
  {
1962
2568
  className: "flopay-shared-input",
@@ -1973,7 +2579,7 @@ function SplitCardFormInner({
1973
2579
  style: inputFieldStyle()
1974
2580
  }
1975
2581
  ) }),
1976
- (0, import_shared4.isAVSFieldVisible)(avsConfig.address_line_2, cc) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: inputWrapStyle(bStyles.addressLine2Input), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2582
+ (0, import_shared5.isAVSFieldVisible)(avsConfig.address_line_2, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: inputWrapStyle(bStyles.addressLine2Input), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1977
2583
  "input",
1978
2584
  {
1979
2585
  className: "flopay-shared-input",
@@ -1989,21 +2595,21 @@ function SplitCardFormInner({
1989
2595
  style: inputFieldStyle()
1990
2596
  }
1991
2597
  ) }),
1992
- ((0, import_shared4.isAVSFieldVisible)(avsConfig.city, cc) || (0, import_shared4.isAVSFieldVisible)(avsConfig.state, cc)) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
2598
+ ((0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) || (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
1993
2599
  display: "flex",
1994
2600
  gap: "0",
1995
2601
  marginTop: "0.5rem"
1996
2602
  }, children: [
1997
- (0, import_shared4.isAVSFieldVisible)(avsConfig.city, cc) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2603
+ (0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
1998
2604
  flex: 1,
1999
2605
  backgroundColor: cardInputBg,
2000
2606
  border: `1px solid ${resolvedBorder}`,
2001
2607
  padding: "10px",
2002
2608
  borderTopLeftRadius: "8px",
2003
2609
  borderBottomLeftRadius: "8px",
2004
- ...(0, import_shared4.isAVSFieldVisible)(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: "8px" },
2610
+ ...(0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) ? { borderRight: "none", borderTopRightRadius: 0, borderBottomRightRadius: 0 } : { borderRadius: "8px" },
2005
2611
  ...isButtons && bStyles.cityInput ? bStyles.cityInput : {}
2006
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2612
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2007
2613
  "input",
2008
2614
  {
2009
2615
  className: "flopay-shared-input",
@@ -2020,16 +2626,16 @@ function SplitCardFormInner({
2020
2626
  style: inputFieldStyle()
2021
2627
  }
2022
2628
  ) }),
2023
- (0, import_shared4.isAVSFieldVisible)(avsConfig.state, cc) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2629
+ (0, import_shared5.isAVSFieldVisible)(avsConfig.state, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2024
2630
  flex: 1,
2025
2631
  backgroundColor: cardInputBg,
2026
2632
  border: `1px solid ${resolvedBorder}`,
2027
2633
  padding: "10px",
2028
2634
  borderTopRightRadius: "8px",
2029
2635
  borderBottomRightRadius: "8px",
2030
- ...(0, import_shared4.isAVSFieldVisible)(avsConfig.city, cc) ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } : { borderRadius: "8px" },
2636
+ ...(0, import_shared5.isAVSFieldVisible)(avsConfig.city, cc) ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0 } : { borderRadius: "8px" },
2031
2637
  ...isButtons && bStyles.stateInput ? bStyles.stateInput : {}
2032
- }, children: stateOpts ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2638
+ }, children: stateOpts ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2033
2639
  "select",
2034
2640
  {
2035
2641
  value: stateValue,
@@ -2043,15 +2649,15 @@ function SplitCardFormInner({
2043
2649
  "data-testid": "flopay-state",
2044
2650
  style: { ...inputFieldStyle(), cursor: "pointer" },
2045
2651
  children: [
2046
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", children: (0, import_shared4.getStateLabel)(cc) }),
2047
- stateOpts.map((s) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: s.code, children: s.name }, s.code))
2652
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: (0, import_shared5.getStateLabel)(cc) }),
2653
+ stateOpts.map((s) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: s.code, children: s.name }, s.code))
2048
2654
  ]
2049
2655
  }
2050
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2656
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2051
2657
  "input",
2052
2658
  {
2053
2659
  className: "flopay-shared-input",
2054
- placeholder: (0, import_shared4.getStateLabel)(cc),
2660
+ placeholder: (0, import_shared5.getStateLabel)(cc),
2055
2661
  autoComplete: "address-level1",
2056
2662
  value: stateValue,
2057
2663
  onChange: (e) => {
@@ -2065,20 +2671,20 @@ function SplitCardFormInner({
2065
2671
  }
2066
2672
  ) })
2067
2673
  ] }),
2068
- ((0, import_shared4.isAVSFieldVisible)(avsConfig.country, cc) || (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, cc)) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
2674
+ ((0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) || (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc)) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2069
2675
  display: "flex",
2070
2676
  flexDirection: avsLayoutProp === "column" ? "column" : "row",
2071
2677
  gap: avsLayoutProp === "column" ? "0.5rem" : "0",
2072
2678
  marginTop: "0.5rem"
2073
2679
  }, children: [
2074
- (0, import_shared4.isAVSFieldVisible)(avsConfig.country, cc) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2680
+ (0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2075
2681
  flex: avsLayoutProp === "row" ? 1 : void 0,
2076
2682
  backgroundColor: cardInputBg,
2077
2683
  border: `1px solid ${resolvedBorder}`,
2078
2684
  padding: "10px",
2079
- ...avsLayoutProp === "row" && (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
2685
+ ...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) ? { borderRadius: "0", borderTopLeftRadius: "8px", borderBottomLeftRadius: "8px", borderRight: "none" } : { borderRadius: "8px" },
2080
2686
  ...isButtons && bStyles.countrySelect ? bStyles.countrySelect : {}
2081
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2687
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2082
2688
  "select",
2083
2689
  {
2084
2690
  value: selectedCountry,
@@ -2093,25 +2699,25 @@ function SplitCardFormInner({
2093
2699
  autoComplete: "country",
2094
2700
  "data-testid": "flopay-country",
2095
2701
  style: { ...inputFieldStyle(), cursor: "pointer" },
2096
- children: import_shared4.COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("option", { value: c.code, children: [
2702
+ children: import_shared5.COUNTRY_OPTIONS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("option", { value: c.code, children: [
2097
2703
  c.flag,
2098
2704
  " ",
2099
2705
  c.name
2100
2706
  ] }, c.code))
2101
2707
  }
2102
2708
  ) }),
2103
- (0, import_shared4.isAVSFieldVisible)(avsConfig.postal_code, cc) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2709
+ (0, import_shared5.isAVSFieldVisible)(avsConfig.postal_code, cc) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2104
2710
  flex: avsLayoutProp === "row" ? 1 : void 0,
2105
2711
  backgroundColor: cardInputBg,
2106
2712
  border: `1px solid ${resolvedBorder}`,
2107
2713
  padding: "10px",
2108
- ...avsLayoutProp === "row" && (0, import_shared4.isAVSFieldVisible)(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: "8px", borderBottomRightRadius: "8px" } : { borderRadius: "8px" },
2714
+ ...avsLayoutProp === "row" && (0, import_shared5.isAVSFieldVisible)(avsConfig.country, cc) ? { borderRadius: "0", borderTopRightRadius: "8px", borderBottomRightRadius: "8px" } : { borderRadius: "8px" },
2109
2715
  ...isButtons && bStyles.zipInput ? bStyles.zipInput : {}
2110
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2716
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2111
2717
  "input",
2112
2718
  {
2113
2719
  className: "flopay-shared-input",
2114
- placeholder: (0, import_shared4.getPostalCodeLabel)(selectedCountry),
2720
+ placeholder: (0, import_shared5.getPostalCodeLabel)(selectedCountry),
2115
2721
  autoComplete: "postal-code",
2116
2722
  value: zipCode,
2117
2723
  onChange: (e) => {
@@ -2128,7 +2734,7 @@ function SplitCardFormInner({
2128
2734
  ] })
2129
2735
  ] });
2130
2736
  })(),
2131
- displayError && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
2737
+ displayError && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
2132
2738
  margin: "0.75rem 0",
2133
2739
  padding: "0.625rem 0.875rem",
2134
2740
  background: "#FEF2F2",
@@ -2142,10 +2748,10 @@ function SplitCardFormInner({
2142
2748
  gap: "0.5rem",
2143
2749
  ...isButtons && bStyles.errorBanner ? bStyles.errorBanner : {}
2144
2750
  }, children: [
2145
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2751
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2146
2752
  displayError
2147
2753
  ] }),
2148
- children ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2754
+ children ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2149
2755
  "button",
2150
2756
  {
2151
2757
  type: "submit",
@@ -2168,7 +2774,7 @@ function SplitCardFormInner({
2168
2774
  children: isSubmitting ? "PROCESSING..." : submitLabel
2169
2775
  }
2170
2776
  ),
2171
- !isButtons && showSecurityFooter && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2777
+ !isButtons && showSecurityFooter && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2172
2778
  backgroundColor: "#EFF9F0",
2173
2779
  borderRadius: "8px",
2174
2780
  padding: "0.75rem",
@@ -2185,11 +2791,11 @@ function SplitCardFormInner({
2185
2791
  const cardButtonSizing = cardButtonContent === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
2186
2792
  const buttonsAnim = viewState === "expanding" ? `flopay-buttons-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-buttons-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : void 0;
2187
2793
  const cardAnim = viewState === "expanding" ? `flopay-card-enter ${TRANSITION_MS}ms cubic-bezier(0, 0, 0.2, 1) both` : viewState === "collapsing" ? `flopay-card-exit ${TRANSITION_MS}ms cubic-bezier(0.4, 0, 0.2, 1) both` : void 0;
2188
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
2189
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayKeyframes, {}),
2190
- overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
2191
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "grid" }, children: [
2192
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
2794
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
2795
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
2796
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
2797
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "grid" }, children: [
2798
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2193
2799
  gridArea: "1 / 1",
2194
2800
  display: "flex",
2195
2801
  flexDirection: "column",
@@ -2198,7 +2804,75 @@ function SplitCardFormInner({
2198
2804
  ...!isButtonsView && !buttonsAnim ? { visibility: "hidden", position: "absolute", pointerEvents: "none", width: "100%" } : {},
2199
2805
  ...buttonsAnim ? { animation: buttonsAnim, pointerEvents: "none" } : {}
2200
2806
  }, children: [
2201
- shouldRenderPayPal && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2807
+ debug && showPayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2808
+ "pre",
2809
+ {
2810
+ "data-testid": "flopay-direct-paypal-gate-debug",
2811
+ style: {
2812
+ margin: 0,
2813
+ padding: "6px 8px",
2814
+ background: "#eef2ff",
2815
+ border: "1px solid #c7d2fe",
2816
+ borderRadius: 6,
2817
+ color: "#111827",
2818
+ font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
2819
+ whiteSpace: "pre-wrap",
2820
+ wordBreak: "break-word"
2821
+ },
2822
+ children: [
2823
+ "FloPay/DirectPayPal-debug (parent gate)",
2824
+ ` showPayPal=${showPayPal}`,
2825
+ ` directPaypalConfigured=${directPaypalConfigured}`,
2826
+ ` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
2827
+ ` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
2828
+ ` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
2829
+ ` hasPaypalStripeInstance=${!!paypalStripeInstance}`
2830
+ ].join("\n")
2831
+ }
2832
+ ),
2833
+ shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2834
+ paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2835
+ "div",
2836
+ {
2837
+ "data-testid": "flopay-paypal-direct-retry-notice",
2838
+ style: {
2839
+ padding: "8px 10px",
2840
+ background: "#fef3c7",
2841
+ border: "1px solid #fcd34d",
2842
+ borderRadius: 6,
2843
+ color: "#78350f",
2844
+ fontSize: 13,
2845
+ lineHeight: 1.4
2846
+ },
2847
+ children: "Please confirm your PayPal payment to complete checkout."
2848
+ }
2849
+ ),
2850
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2851
+ DirectPayPalButton,
2852
+ {
2853
+ sessionId,
2854
+ billingApiUrl: resolvedBillingApiUrl,
2855
+ email: resolvedAccount.email,
2856
+ clientId: directPaypal.clientId,
2857
+ environment: directPaypal.environment,
2858
+ currency: currency.toUpperCase(),
2859
+ isSubscription,
2860
+ onTokenizedBody: dispatchTokenizedBody,
2861
+ onComplete,
2862
+ onErrorChange: updateError,
2863
+ onDecline,
2864
+ onButtonClick,
2865
+ runBeforeButtonClick,
2866
+ isProcessing: isSubmitting,
2867
+ onLoadStateChange: setDirectPaypalReady,
2868
+ session: session ?? null,
2869
+ existingOrderId: paypalDirectRetry?.orderId,
2870
+ debug
2871
+ },
2872
+ paypalDirectRetry?.orderId ?? "fresh"
2873
+ )
2874
+ ] }),
2875
+ shouldRenderStripePayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2202
2876
  PayPalButtonInner,
2203
2877
  {
2204
2878
  sessionId,
@@ -2213,7 +2887,7 @@ function SplitCardFormInner({
2213
2887
  onLoadStateChange: setPaypalLoadState
2214
2888
  }
2215
2889
  ) }),
2216
- shouldRenderWallets ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2890
+ shouldRenderWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2217
2891
  WalletButtonInner,
2218
2892
  {
2219
2893
  sessionId,
@@ -2228,8 +2902,8 @@ function SplitCardFormInner({
2228
2902
  runBeforeButtonClick,
2229
2903
  onLoadStateChange: setWalletLoadState
2230
2904
  }
2231
- ) }) : shouldShowWallets ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
2232
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2905
+ ) }) : shouldShowWallets ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT, borderRadius: 8, background: "#e5e7eb", animation: "flopay-pulse 1.5s ease-in-out infinite" } }) : null,
2906
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2233
2907
  "button",
2234
2908
  {
2235
2909
  type: "button",
@@ -2267,10 +2941,10 @@ function SplitCardFormInner({
2267
2941
  onMouseUp: (e) => {
2268
2942
  e.currentTarget.style.transform = "scale(1)";
2269
2943
  },
2270
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardButtonContentSlot, { content: cardButtonContent })
2944
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardButtonContentSlot, { content: cardButtonContent })
2271
2945
  }
2272
2946
  ),
2273
- displayError && viewState === "buttons" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
2947
+ displayError && viewState === "buttons" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "alert", "data-testid": "flopay-error", style: {
2274
2948
  margin: "0.25rem 0",
2275
2949
  padding: "0.625rem 0.875rem",
2276
2950
  background: "#FEF2F2",
@@ -2284,11 +2958,11 @@ function SplitCardFormInner({
2284
2958
  gap: "0.5rem",
2285
2959
  ...bStyles.errorBanner ? bStyles.errorBanner : {}
2286
2960
  }, children: [
2287
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2961
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
2288
2962
  displayError
2289
2963
  ] })
2290
2964
  ] }),
2291
- isCardView && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
2965
+ isCardView && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
2292
2966
  gridArea: "1 / 1",
2293
2967
  ...cardAnim ? { animation: cardAnim } : {},
2294
2968
  ...viewState === "collapsing" ? { pointerEvents: "none" } : {}
@@ -2296,37 +2970,111 @@ function SplitCardFormInner({
2296
2970
  ] })
2297
2971
  ] });
2298
2972
  }
2299
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
2300
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FloPayKeyframes, {}),
2301
- overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
2302
- shouldRenderWallets && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2303
- WalletButtonInner,
2304
- {
2305
- sessionId,
2306
- email: resolvedAccount.email,
2307
- billingApiUrl: resolvedBillingApiUrl,
2308
- showApplePay,
2309
- showGooglePay,
2310
- onTokenizedBody: dispatchTokenizedBody,
2311
- onErrorChange: updateError,
2312
- onDecline,
2313
- onLoadStateChange: setWalletLoadState
2314
- }
2315
- ) }),
2316
- shouldRenderPayPal && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2317
- PayPalButtonInner,
2318
- {
2319
- sessionId,
2320
- email: resolvedAccount.email,
2321
- billingApiUrl: resolvedBillingApiUrl,
2322
- onTokenizedBody: dispatchTokenizedBody,
2323
- onErrorChange: updateError,
2324
- isProcessing: isSubmitting,
2325
- onDecline,
2326
- onLoadStateChange: setPaypalLoadState
2327
- }
2328
- ) }),
2329
- (shouldDisplayWalletRow || shouldDisplayPayPalRow) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: {
2973
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
2974
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayKeyframes, {}),
2975
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ProcessingOverlay, { status: overlayStatus, errorMessage: displayError }),
2976
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
2977
+ debug && showPayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2978
+ "pre",
2979
+ {
2980
+ "data-testid": "flopay-direct-paypal-gate-debug-default",
2981
+ style: {
2982
+ margin: 0,
2983
+ padding: "6px 8px",
2984
+ background: "#eef2ff",
2985
+ border: "1px solid #c7d2fe",
2986
+ borderRadius: 6,
2987
+ color: "#111827",
2988
+ font: "11px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace",
2989
+ whiteSpace: "pre-wrap",
2990
+ wordBreak: "break-word"
2991
+ },
2992
+ children: [
2993
+ "FloPay/DirectPayPal-debug (parent gate)",
2994
+ ` showPayPal=${showPayPal}`,
2995
+ ` directPaypalConfigured=${directPaypalConfigured}`,
2996
+ ` inAppBrowserDetected=${String(inAppBrowserDetected)}`,
2997
+ ` shouldRenderDirectPayPal=${shouldRenderDirectPayPal}`,
2998
+ ` shouldRenderStripePayPal=${shouldRenderStripePayPal}`,
2999
+ ` hasPaypalStripeInstance=${!!paypalStripeInstance}`
3000
+ ].join("\n")
3001
+ }
3002
+ ),
3003
+ shouldRenderDirectPayPal && directPaypal && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3004
+ paypalDirectRetry && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3005
+ "div",
3006
+ {
3007
+ "data-testid": "flopay-paypal-direct-retry-notice-default",
3008
+ style: {
3009
+ padding: "8px 10px",
3010
+ background: "#fef3c7",
3011
+ border: "1px solid #fcd34d",
3012
+ borderRadius: 6,
3013
+ color: "#78350f",
3014
+ fontSize: 13,
3015
+ lineHeight: 1.4
3016
+ },
3017
+ children: "Please confirm your PayPal payment to complete checkout."
3018
+ }
3019
+ ),
3020
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3021
+ DirectPayPalButton,
3022
+ {
3023
+ sessionId,
3024
+ billingApiUrl: resolvedBillingApiUrl,
3025
+ email: resolvedAccount.email,
3026
+ clientId: directPaypal.clientId,
3027
+ environment: directPaypal.environment,
3028
+ currency: currency.toUpperCase(),
3029
+ isSubscription,
3030
+ onTokenizedBody: dispatchTokenizedBody,
3031
+ onComplete,
3032
+ onErrorChange: updateError,
3033
+ onDecline,
3034
+ onButtonClick,
3035
+ runBeforeButtonClick,
3036
+ isProcessing: isSubmitting,
3037
+ onLoadStateChange: setDirectPaypalReady,
3038
+ session: session ?? null,
3039
+ existingOrderId: paypalDirectRetry?.orderId,
3040
+ debug
3041
+ },
3042
+ paypalDirectRetry?.orderId ?? "fresh"
3043
+ )
3044
+ ] }),
3045
+ shouldRenderStripePayPal && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: paypalStripeInstance, options: paypalOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3046
+ PayPalButtonInner,
3047
+ {
3048
+ sessionId,
3049
+ email: resolvedAccount.email,
3050
+ billingApiUrl: resolvedBillingApiUrl,
3051
+ onTokenizedBody: dispatchTokenizedBody,
3052
+ onErrorChange: updateError,
3053
+ isProcessing: isSubmitting,
3054
+ onButtonClick,
3055
+ onDecline,
3056
+ runBeforeButtonClick,
3057
+ onLoadStateChange: setPaypalLoadState
3058
+ }
3059
+ ) }),
3060
+ shouldRenderWallets && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_stripe_js.Elements, { stripe: stripeInstance, options: walletOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3061
+ WalletButtonInner,
3062
+ {
3063
+ sessionId,
3064
+ email: resolvedAccount.email,
3065
+ billingApiUrl: resolvedBillingApiUrl,
3066
+ showApplePay,
3067
+ showGooglePay,
3068
+ onTokenizedBody: dispatchTokenizedBody,
3069
+ onErrorChange: updateError,
3070
+ onButtonClick,
3071
+ onDecline,
3072
+ runBeforeButtonClick,
3073
+ onLoadStateChange: setWalletLoadState
3074
+ }
3075
+ ) })
3076
+ ] }),
3077
+ (shouldDisplayWalletRow || shouldDisplayPayPalRow) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
2330
3078
  display: "flex",
2331
3079
  alignItems: "center",
2332
3080
  gap: "0.75rem",
@@ -2334,17 +3082,17 @@ function SplitCardFormInner({
2334
3082
  color: "#999",
2335
3083
  fontSize: "0.85rem"
2336
3084
  }, children: [
2337
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
2338
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "or pay with card" }),
2339
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
3085
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } }),
3086
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "or pay with card" }),
3087
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, height: 1, backgroundColor: "#ddd" } })
2340
3088
  ] }),
2341
3089
  cardFormBlock
2342
3090
  ] });
2343
3091
  }
2344
3092
 
2345
3093
  // src/saved-payment-flow.ts
2346
- var import_js2 = require("@flopay/js");
2347
- var import_shared6 = require("@flopay/shared");
3094
+ var import_js3 = require("@flopay/js");
3095
+ var import_shared7 = require("@flopay/shared");
2348
3096
  var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
2349
3097
  function getRedirectResultFromCheckoutProcessError(error) {
2350
3098
  if (!error?.type || !error.threeDSecureToken) {
@@ -2361,9 +3109,11 @@ function getRedirectResultFromCheckoutProcessError(error) {
2361
3109
  }
2362
3110
  function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
2363
3111
  const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
3112
+ const rawMessage = error?.message ?? fallbackMessage;
3113
+ const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
2364
3114
  return Object.assign(
2365
- new import_shared6.FloPayError(
2366
- error?.message ?? fallbackMessage,
3115
+ new import_shared7.FloPayError(
3116
+ message,
2367
3117
  "api_error",
2368
3118
  {
2369
3119
  code: error?.gatewayErrorCode
@@ -2417,16 +3167,19 @@ function getRedirectTokenFromProcessResponse(json, options) {
2417
3167
  return candidate;
2418
3168
  }
2419
3169
  }
2420
- const nestedGatewayData = nestedRecord.gatewayData;
2421
- if (nestedGatewayData && typeof nestedGatewayData === "object") {
2422
- const nestedGatewayDataRecord = nestedGatewayData;
2423
- const gatewayCandidates = [
2424
- nestedGatewayDataRecord.stripeClientSecret,
2425
- nestedGatewayDataRecord.clientSecret
2426
- ];
2427
- for (const candidate of gatewayCandidates) {
2428
- if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
2429
- return candidate;
3170
+ const nestedGateways = nestedRecord.gateways;
3171
+ if (nestedGateways && typeof nestedGateways === "object") {
3172
+ const stripeGateway = nestedGateways.stripe;
3173
+ if (stripeGateway && typeof stripeGateway === "object") {
3174
+ const stripeRecord = stripeGateway;
3175
+ const gatewayCandidates = [
3176
+ stripeRecord.stripeClientSecret,
3177
+ stripeRecord.clientSecret
3178
+ ];
3179
+ for (const candidate of gatewayCandidates) {
3180
+ if (typeof candidate === "string" && candidate.length > 0 && (!options?.requirePaymentIntentClientSecret || isStripePaymentIntentClientSecret(candidate))) {
3181
+ return candidate;
3182
+ }
2430
3183
  }
2431
3184
  }
2432
3185
  }
@@ -2451,9 +3204,9 @@ async function recover3DSRedirectResult({
2451
3204
  return null;
2452
3205
  }
2453
3206
  try {
2454
- const api = new import_js2.PaymentAPI(billingApiUrl);
3207
+ const api = new import_js3.PaymentAPI(billingApiUrl);
2455
3208
  const unified = await api.getUnifiedCheckoutSession(sessionId);
2456
- const refreshedToken = unified.provider === "stripe" ? unified.data.stripe?.clientSecret : void 0;
3209
+ const refreshedToken = unified.data.stripe?.clientSecret;
2457
3210
  if (isStripePaymentIntentClientSecret(refreshedToken)) {
2458
3211
  return {
2459
3212
  type: "3ds_required",
@@ -2479,7 +3232,7 @@ async function processSavedPaymentForMode({
2479
3232
  const lastName = session.customer?.lastName ?? session.accountData?.lastName ?? "";
2480
3233
  const country = session.customer?.country ?? session.accountData?.country ?? void 0;
2481
3234
  const zip = session.customer?.zip ?? session.accountData?.zip ?? void 0;
2482
- const api = new import_js2.PaymentAPI(baseUrl);
3235
+ const api = new import_js3.PaymentAPI(baseUrl);
2483
3236
  const response = await retryOnceOnFetchFailure(() => api.processPayment(customerId, {
2484
3237
  sessionId: resolvedSessionId,
2485
3238
  tokenizedData,
@@ -2508,7 +3261,7 @@ async function processSavedPaymentForMode({
2508
3261
  if (json?.type === "paypal_redirect_required" || json?.type === "3ds_required") {
2509
3262
  const redirectToken = getRedirectTokenFromProcessResponse(json);
2510
3263
  if (!redirectToken) {
2511
- throw new import_shared6.FloPayError(
3264
+ throw new import_shared7.FloPayError(
2512
3265
  "Authentication is required but no redirect token was provided.",
2513
3266
  "api_error",
2514
3267
  { code: "authentication_required" }
@@ -2530,7 +3283,7 @@ async function processSavedPaymentForMode({
2530
3283
  return recoveredRedirect;
2531
3284
  }
2532
3285
  throw Object.assign(
2533
- new import_shared6.FloPayError(
3286
+ new import_shared7.FloPayError(
2534
3287
  "Your card requires authentication. Please enter your payment details below.",
2535
3288
  "api_error",
2536
3289
  { code: "authentication_required" }
@@ -2538,7 +3291,7 @@ async function processSavedPaymentForMode({
2538
3291
  { checkoutMethod: "card" }
2539
3292
  );
2540
3293
  }
2541
- throw new import_shared6.FloPayError(
3294
+ throw new import_shared7.FloPayError(
2542
3295
  json?.message ?? "Payment failed. Please try again.",
2543
3296
  "api_error",
2544
3297
  {
@@ -2558,13 +3311,13 @@ async function processSavedPaymentWithIntent({
2558
3311
  const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
2559
3312
  if (!customerEmail) {
2560
3313
  throw Object.assign(
2561
- new import_shared6.FloPayError("Customer email is required to create a payment intent.", "validation_error", {
3314
+ new import_shared7.FloPayError("Customer email is required to create a payment intent.", "validation_error", {
2562
3315
  param: "email"
2563
3316
  }),
2564
3317
  { checkoutMethod: "card" }
2565
3318
  );
2566
3319
  }
2567
- const api = new import_js2.PaymentAPI(billingApiUrl);
3320
+ const api = new import_js3.PaymentAPI(billingApiUrl);
2568
3321
  const intentResponse = await retryOnceOnFetchFailure(() => api.createPaymentIntent(
2569
3322
  sessionId,
2570
3323
  customerEmail,
@@ -2586,7 +3339,7 @@ async function processSavedPaymentWithIntent({
2586
3339
  });
2587
3340
  if (!intentClientSecret) {
2588
3341
  throw Object.assign(
2589
- new import_shared6.FloPayError("No client secret in payment intent response.", "api_error"),
3342
+ new import_shared7.FloPayError("No client secret in payment intent response.", "api_error"),
2590
3343
  { checkoutMethod: "card" }
2591
3344
  );
2592
3345
  }
@@ -2609,7 +3362,7 @@ async function processSavedPaymentWithIntent({
2609
3362
  const confirmedPaymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? paymentMethodId;
2610
3363
  if (!confirmedPaymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
2611
3364
  throw Object.assign(
2612
- new import_shared6.FloPayError(
3365
+ new import_shared7.FloPayError(
2613
3366
  `Unfortunately, your payment could not be processed. Please try again using a different payment method or contact your bank for assistance. If the issue persists, feel free to reach out to us for support.`,
2614
3367
  "api_error",
2615
3368
  {
@@ -2657,12 +3410,12 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2657
3410
  }) {
2658
3411
  const stripe = flopay?.getRawProvider();
2659
3412
  if (!stripe) {
2660
- throw new import_shared6.FloPayError("Payment provider is not available.", "api_error");
3413
+ throw new import_shared7.FloPayError("Payment provider is not available.", "api_error");
2661
3414
  }
2662
3415
  if (redirectResult.type === "3ds_required") {
2663
3416
  if (!attempt3DS || !redirectResult.threeDSecureToken) {
2664
3417
  throw Object.assign(
2665
- new import_shared6.FloPayError(
3418
+ new import_shared7.FloPayError(
2666
3419
  "Your card requires authentication. Please enter your payment details below.",
2667
3420
  "api_error",
2668
3421
  { code: "authentication_required" }
@@ -2678,7 +3431,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2678
3431
  );
2679
3432
  if (retrieveError) {
2680
3433
  throw Object.assign(
2681
- new import_shared6.FloPayError(
3434
+ new import_shared7.FloPayError(
2682
3435
  retrieveError.message ?? "Failed to retrieve 3DS payment status.",
2683
3436
  "api_error",
2684
3437
  { code: retrieveError.code }
@@ -2704,7 +3457,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2704
3457
  );
2705
3458
  if (confirmError) {
2706
3459
  throw Object.assign(
2707
- new import_shared6.FloPayError(
3460
+ new import_shared7.FloPayError(
2708
3461
  confirmError.message ?? "3DS authentication failed.",
2709
3462
  "api_error",
2710
3463
  { code: confirmError.code }
@@ -2719,7 +3472,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2719
3472
  });
2720
3473
  if (nextActionError) {
2721
3474
  throw Object.assign(
2722
- new import_shared6.FloPayError(
3475
+ new import_shared7.FloPayError(
2723
3476
  nextActionError.message ?? "3DS authentication failed.",
2724
3477
  "api_error",
2725
3478
  { code: nextActionError.code }
@@ -2759,7 +3512,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2759
3512
  });
2760
3513
  }
2761
3514
  throw Object.assign(
2762
- new import_shared6.FloPayError("3DS authentication did not complete successfully.", "api_error"),
3515
+ new import_shared7.FloPayError("3DS authentication did not complete successfully.", "api_error"),
2763
3516
  { checkoutMethod: "card" }
2764
3517
  );
2765
3518
  }
@@ -2767,7 +3520,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2767
3520
  const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
2768
3521
  if (!paypalStripe) {
2769
3522
  throw Object.assign(
2770
- new import_shared6.FloPayError("PayPal is not available.", "api_error"),
3523
+ new import_shared7.FloPayError("PayPal is not available.", "api_error"),
2771
3524
  { checkoutMethod: "paypal" }
2772
3525
  );
2773
3526
  }
@@ -2777,7 +3530,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2777
3530
  });
2778
3531
  if (error2) {
2779
3532
  throw Object.assign(
2780
- new import_shared6.FloPayError(
3533
+ new import_shared7.FloPayError(
2781
3534
  error2.message ?? "PayPal authorization failed.",
2782
3535
  "api_error",
2783
3536
  { code: error2.code }
@@ -2800,7 +3553,7 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2800
3553
  });
2801
3554
  if (error) {
2802
3555
  throw Object.assign(
2803
- new import_shared6.FloPayError(
3556
+ new import_shared7.FloPayError(
2804
3557
  error.message ?? "PayPal authorization failed.",
2805
3558
  "api_error",
2806
3559
  { code: error.code }
@@ -2813,33 +3566,48 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
2813
3566
  checkoutMethod: "paypal"
2814
3567
  };
2815
3568
  }
2816
- throw new import_shared6.FloPayError("Unsupported payment redirect state.", "api_error");
3569
+ throw new import_shared7.FloPayError("Unsupported payment redirect state.", "api_error");
2817
3570
  }
2818
3571
  function normalizeSavedPaymentError(err) {
2819
- if (err instanceof import_shared6.FloPayError) {
3572
+ if (err instanceof import_shared7.FloPayError) {
3573
+ const friendly = applyFriendlyMessageOverride(err.message);
3574
+ if (friendly && friendly !== err.message) {
3575
+ return Object.assign(
3576
+ new import_shared7.FloPayError(friendly, err.type, {
3577
+ code: err.code,
3578
+ declineCode: err.declineCode,
3579
+ param: err.param,
3580
+ statusCode: err.statusCode
3581
+ }),
3582
+ { checkoutMethod: err.checkoutMethod }
3583
+ );
3584
+ }
2820
3585
  return err;
2821
3586
  }
2822
- return new import_shared6.FloPayError(
2823
- err instanceof Error ? err.message : "Payment failed. Please try again.",
2824
- "api_error"
2825
- );
3587
+ const rawMessage = err instanceof Error ? err.message : "Payment failed. Please try again.";
3588
+ const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
3589
+ return new import_shared7.FloPayError(message, "api_error");
2826
3590
  }
2827
3591
  function resolveSavedPaymentPublishableKeys(unified) {
2828
- let publishableKey;
2829
- let paypalPublishableKey;
2830
- if (unified.provider === "stripe") {
2831
- publishableKey = unified.data.stripe?.publishableKey;
2832
- paypalPublishableKey = unified.data.stripe?.paypalPublishableKey ?? void 0;
2833
- }
2834
- if (!publishableKey) {
2835
- throw new import_shared6.FloPayError(
2836
- "No publishable key found in the checkout session. Ensure the session includes gatewayData.publishableKey.",
3592
+ const publishableKey = unified.data.stripe?.publishableKey;
3593
+ const hasDirectPaypal = Boolean(unified.data.paypal?.publishableKey);
3594
+ if (!publishableKey && !hasDirectPaypal) {
3595
+ throw new import_shared7.FloPayError(
3596
+ "Session advertises no supported gateways (expected `gateways.stripe` and/or `gateways.paypal`).",
2837
3597
  "validation_error"
2838
3598
  );
2839
3599
  }
3600
+ if (!publishableKey) {
3601
+ return {};
3602
+ }
2840
3603
  return {
2841
3604
  publishableKey,
2842
- paypalPublishableKey
3605
+ // Direct-PayPal sessions can still use Stripe's PayPal Element for the
3606
+ // saved-PM redirect leg. Prefer the dedicated Stripe-PayPal sub-account
3607
+ // publishable key when the backend advertises one; fall back to the
3608
+ // primary Stripe publishable key so the resume flow still has a Stripe
3609
+ // instance to drive Stripe's PayPal PI.
3610
+ paypalPublishableKey: unified.data.stripe?.paypalPublishableKey ?? publishableKey
2843
3611
  };
2844
3612
  }
2845
3613
  async function loadSavedPaymentProviders({
@@ -2848,13 +3616,16 @@ async function loadSavedPaymentProviders({
2848
3616
  billingApiUrl,
2849
3617
  locale
2850
3618
  }) {
3619
+ if (!publishableKey) {
3620
+ return { flopay: null, paypalFlopay: null };
3621
+ }
2851
3622
  const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
2852
3623
  const [instance, paypalInstanceOrError] = await Promise.all([
2853
- (0, import_js2.loadFloPay)(publishableKey, {
3624
+ (0, import_js3.loadFloPay)(publishableKey, {
2854
3625
  billingApiUrl,
2855
3626
  locale
2856
3627
  }),
2857
- needsSeparatePaypal ? (0, import_js2.loadFloPay)(paypalPublishableKey, {
3628
+ needsSeparatePaypal ? (0, import_js3.loadFloPay)(paypalPublishableKey, {
2858
3629
  billingApiUrl,
2859
3630
  locale
2860
3631
  }).catch((err) => {
@@ -2869,13 +3640,26 @@ async function loadSavedPaymentProviders({
2869
3640
  }
2870
3641
 
2871
3642
  // src/flopay-checkout.tsx
2872
- var import_jsx_runtime6 = require("react/jsx-runtime");
3643
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2873
3644
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2 = 44;
2874
3645
  var PAYPAL_RESUME_STORAGE_KEY = "flopay_checkout_saved_payment_resume";
2875
3646
  var sessionInflightMap = /* @__PURE__ */ new Map();
2876
3647
  function sleep(ms) {
2877
3648
  return new Promise((resolve) => setTimeout(resolve, ms));
2878
3649
  }
3650
+ function resolveDirectPaypalConfig(unified) {
3651
+ const clientId = unified?.data.paypal?.publishableKey;
3652
+ if (!clientId) return void 0;
3653
+ return {
3654
+ clientId,
3655
+ environment: unified?.data.paypal?.environment
3656
+ };
3657
+ }
3658
+ function isPayPalOnlyUnified(unified) {
3659
+ if (!unified) return false;
3660
+ if (unified.data.stripe?.publishableKey) return false;
3661
+ return Boolean(resolveDirectPaypalConfig(unified)?.clientId);
3662
+ }
2879
3663
  function canUseStorage() {
2880
3664
  return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
2881
3665
  }
@@ -2949,6 +3733,7 @@ function FloPayCheckout({
2949
3733
  showPayPal = true,
2950
3734
  showApplePay = true,
2951
3735
  showGooglePay = true,
3736
+ debug = false,
2952
3737
  layout,
2953
3738
  buttonsTheme,
2954
3739
  buttonsStyles,
@@ -2969,81 +3754,81 @@ function FloPayCheckout({
2969
3754
  renderConfirmButton,
2970
3755
  onSessionCompleted
2971
3756
  }) {
2972
- const resolvedBillingUrl = (0, import_shared7.resolveBillingApiUrl)(billingApiUrl);
3757
+ const resolvedBillingUrl = (0, import_shared8.resolveBillingApiUrl)(billingApiUrl);
2973
3758
  const checkoutType = createSessionParams ? "embedded_checkout" : "standard_checkout";
2974
3759
  const checkoutLayout = children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout";
2975
- const [unified, setUnified] = (0, import_react8.useState)(null);
2976
- const [flopay, setFloPay] = (0, import_react8.useState)(null);
2977
- const flopayRef = (0, import_react8.useRef)(null);
2978
- const [paypalFlopay, setPaypalFloPay] = (0, import_react8.useState)(null);
2979
- const paypalFlopayRef = (0, import_react8.useRef)(null);
2980
- const [session, setSession] = (0, import_react8.useState)(null);
2981
- const [resolvedSessionId, setResolvedSessionId] = (0, import_react8.useState)(sessionIdProp ?? "");
3760
+ const [unified, setUnified] = (0, import_react9.useState)(null);
3761
+ const [flopay, setFloPay] = (0, import_react9.useState)(null);
3762
+ const flopayRef = (0, import_react9.useRef)(null);
3763
+ const [paypalFlopay, setPaypalFloPay] = (0, import_react9.useState)(null);
3764
+ const paypalFlopayRef = (0, import_react9.useRef)(null);
3765
+ const [session, setSession] = (0, import_react9.useState)(null);
3766
+ const [resolvedSessionId, setResolvedSessionId] = (0, import_react9.useState)(sessionIdProp ?? "");
2982
3767
  const activeSessionId = sessionIdProp ?? resolvedSessionId;
2983
3768
  const initSessionDependency = createSessionParams ? "" : activeSessionId;
2984
- const [isLoading, setIsLoading] = (0, import_react8.useState)(true);
2985
- const [loadError, setLoadError] = (0, import_react8.useState)(null);
2986
- const [currentMode, setCurrentMode] = (0, import_react8.useState)("full");
2987
- const [confirmProcessing, setConfirmProcessing] = (0, import_react8.useState)(false);
2988
- const [modeError, setModeError] = (0, import_react8.useState)(initialErrorMessage);
2989
- const [modeOverlayStatus, setModeOverlayStatus] = (0, import_react8.useState)(null);
2990
- const [modeOverlayError, setModeOverlayError] = (0, import_react8.useState)(null);
2991
- const [createSessionPatch, setCreateSessionPatch] = (0, import_react8.useState)(void 0);
2992
- const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react8.useState)("");
2993
- const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react8.useState)(false);
2994
- const autoCheckoutAttempted = (0, import_react8.useRef)(false);
2995
- const paypalResumeAttempted = (0, import_react8.useRef)(false);
2996
- const savedPaymentKeysRef = (0, import_react8.useRef)(null);
2997
- const onCompleteRef = (0, import_react8.useRef)(onComplete);
3769
+ const [isLoading, setIsLoading] = (0, import_react9.useState)(true);
3770
+ const [loadError, setLoadError] = (0, import_react9.useState)(null);
3771
+ const [currentMode, setCurrentMode] = (0, import_react9.useState)("full");
3772
+ const [confirmProcessing, setConfirmProcessing] = (0, import_react9.useState)(false);
3773
+ const [modeError, setModeError] = (0, import_react9.useState)(initialErrorMessage);
3774
+ const [modeOverlayStatus, setModeOverlayStatus] = (0, import_react9.useState)(null);
3775
+ const [modeOverlayError, setModeOverlayError] = (0, import_react9.useState)(null);
3776
+ const [createSessionPatch, setCreateSessionPatch] = (0, import_react9.useState)(void 0);
3777
+ const [createSessionPatchBaseHash, setCreateSessionPatchBaseHash] = (0, import_react9.useState)("");
3778
+ const [cardBootstrapPending, setCardBootstrapPending] = (0, import_react9.useState)(false);
3779
+ const autoCheckoutAttempted = (0, import_react9.useRef)(false);
3780
+ const paypalResumeAttempted = (0, import_react9.useRef)(false);
3781
+ const savedPaymentKeysRef = (0, import_react9.useRef)(null);
3782
+ const onCompleteRef = (0, import_react9.useRef)(onComplete);
2998
3783
  onCompleteRef.current = onComplete;
2999
- const onErrorRef = (0, import_react8.useRef)(onError);
3784
+ const onErrorRef = (0, import_react9.useRef)(onError);
3000
3785
  onErrorRef.current = onError;
3001
- const onDeclineRef = (0, import_react8.useRef)(onDecline);
3786
+ const onDeclineRef = (0, import_react9.useRef)(onDecline);
3002
3787
  onDeclineRef.current = onDecline;
3003
- const onSessionCompletedRef = (0, import_react8.useRef)(onSessionCompleted);
3788
+ const onSessionCompletedRef = (0, import_react9.useRef)(onSessionCompleted);
3004
3789
  onSessionCompletedRef.current = onSessionCompleted;
3005
- (0, import_react8.useEffect)(() => {
3790
+ (0, import_react9.useEffect)(() => {
3006
3791
  console.info("[FloPay] Checkout initialized", {
3007
- sdk_version: import_shared7.SDK_VERSION,
3792
+ sdk_version: import_shared8.SDK_VERSION,
3008
3793
  checkout_type: checkoutType,
3009
3794
  checkout_layout: checkoutLayout,
3010
3795
  billing_api_url: resolvedBillingUrl
3011
3796
  });
3012
3797
  }, [checkoutLayout, checkoutType, resolvedBillingUrl]);
3013
- const baseCreateSessionHash = (0, import_react8.useMemo)(
3798
+ const baseCreateSessionHash = (0, import_react9.useMemo)(
3014
3799
  () => createSessionParams ? hashCreateParams(createSessionParams) : "",
3015
3800
  [createSessionParams]
3016
3801
  );
3017
- const activeCreateSessionPatch = (0, import_react8.useMemo)(
3802
+ const activeCreateSessionPatch = (0, import_react9.useMemo)(
3018
3803
  () => createSessionPatchBaseHash === baseCreateSessionHash ? createSessionPatch : void 0,
3019
3804
  [createSessionPatch, createSessionPatchBaseHash, baseCreateSessionHash]
3020
3805
  );
3021
- const effectiveCreateSessionBase = (0, import_react8.useMemo)(
3806
+ const effectiveCreateSessionBase = (0, import_react9.useMemo)(
3022
3807
  () => createSessionParams ? mergeInlineSessionPatch(createSessionParams, activeCreateSessionPatch) : void 0,
3023
3808
  [createSessionParams, activeCreateSessionPatch]
3024
3809
  );
3025
3810
  const effectiveCreateSessionMode = checkoutModeProp ?? effectiveCreateSessionBase?.checkoutMode ?? "full";
3026
- const effectiveCreateSession = (0, import_react8.useMemo)(
3811
+ const effectiveCreateSession = (0, import_react9.useMemo)(
3027
3812
  () => effectiveCreateSessionBase ? {
3028
3813
  ...effectiveCreateSessionBase,
3029
3814
  checkoutMode: effectiveCreateSessionMode
3030
3815
  } : void 0,
3031
3816
  [effectiveCreateSessionBase, effectiveCreateSessionMode]
3032
3817
  );
3033
- (0, import_react8.useEffect)(() => {
3818
+ (0, import_react9.useEffect)(() => {
3034
3819
  setCreateSessionPatch(void 0);
3035
3820
  setCreateSessionPatchBaseHash(baseCreateSessionHash);
3036
3821
  }, [baseCreateSessionHash]);
3037
- (0, import_react8.useEffect)(() => {
3822
+ (0, import_react9.useEffect)(() => {
3038
3823
  setModeError(initialErrorMessage);
3039
3824
  }, [initialErrorMessage]);
3040
- const emitDecline = (0, import_react8.useCallback)(
3825
+ const emitDecline = (0, import_react9.useCallback)(
3041
3826
  (method, input, overrides) => {
3042
3827
  onDeclineRef.current?.(buildDeclineEvent(method, input, overrides));
3043
3828
  },
3044
3829
  []
3045
3830
  );
3046
- const runSavedPaymentFlow = (0, import_react8.useCallback)(
3831
+ const runSavedPaymentFlow = (0, import_react9.useCallback)(
3047
3832
  async (sess, options) => {
3048
3833
  setModeError(null);
3049
3834
  setModeOverlayError(null);
@@ -3053,7 +3838,7 @@ function FloPayCheckout({
3053
3838
  const redirectResult = getRedirectResultFromCheckoutProcessError(options?.initialAutoProcessingError);
3054
3839
  let paymentResult;
3055
3840
  if (redirectResult) {
3056
- if (redirectResult.type === "paypal_redirect_required" && savedPaymentKeysRef.current) {
3841
+ if (redirectResult.type === "paypal_redirect_required" && savedPaymentKeysRef.current?.publishableKey) {
3057
3842
  persistPayPalResumeState({
3058
3843
  sessionId: activeSessionId2,
3059
3844
  publishableKey: savedPaymentKeysRef.current.publishableKey,
@@ -3072,12 +3857,12 @@ function FloPayCheckout({
3072
3857
  clearPayPalResumeState();
3073
3858
  }
3074
3859
  } else if (options?.initialAutoProcessingPending) {
3075
- const api = new import_js3.PaymentAPI(resolvedBillingUrl);
3860
+ const api = new import_js4.PaymentAPI(resolvedBillingUrl);
3076
3861
  const completed = await api.waitForCheckoutSessionCompletion(options.initialAutoProcessingPending.sessionId, {
3077
3862
  initialDelayMs: options.initialAutoProcessingPending.retryAfterMs
3078
3863
  });
3079
3864
  if (completed.data.session?.status !== "complete") {
3080
- throw new import_shared7.FloPayError("Automatic payment failed. Please try again.", "api_error", {
3865
+ throw new import_shared8.FloPayError("Automatic payment failed. Please try again.", "api_error", {
3081
3866
  code: completed.data.session?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
3082
3867
  });
3083
3868
  }
@@ -3105,7 +3890,7 @@ function FloPayCheckout({
3105
3890
  if (result.type === "success") {
3106
3891
  paymentResult = result.result;
3107
3892
  } else {
3108
- if (result.type === "paypal_redirect_required" && savedPaymentKeysRef.current) {
3893
+ if (result.type === "paypal_redirect_required" && savedPaymentKeysRef.current?.publishableKey) {
3109
3894
  persistPayPalResumeState({
3110
3895
  sessionId: activeSessionId2,
3111
3896
  publishableKey: savedPaymentKeysRef.current.publishableKey,
@@ -3161,7 +3946,7 @@ function FloPayCheckout({
3161
3946
  resolvedBillingUrl
3162
3947
  ]
3163
3948
  );
3164
- (0, import_react8.useEffect)(() => {
3949
+ (0, import_react9.useEffect)(() => {
3165
3950
  if (typeof window === "undefined" || paypalResumeAttempted.current) {
3166
3951
  return;
3167
3952
  }
@@ -3183,7 +3968,7 @@ function FloPayCheckout({
3183
3968
  try {
3184
3969
  if (params.get("redirect_status") === "failed") {
3185
3970
  throw Object.assign(
3186
- new import_shared7.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
3971
+ new import_shared8.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
3187
3972
  { checkoutMethod: "paypal" }
3188
3973
  );
3189
3974
  }
@@ -3196,17 +3981,17 @@ function FloPayCheckout({
3196
3981
  billingApiUrl: resolvedBillingUrl,
3197
3982
  locale
3198
3983
  });
3199
- const paypalStripe = (resumePaypalFlopay ?? resumeFlopay).getRawProvider();
3984
+ const paypalStripe = (resumePaypalFlopay ?? resumeFlopay)?.getRawProvider();
3200
3985
  if (!paypalStripe) {
3201
3986
  throw Object.assign(
3202
- new import_shared7.FloPayError("PayPal is not available.", "api_error"),
3987
+ new import_shared8.FloPayError("PayPal is not available.", "api_error"),
3203
3988
  { checkoutMethod: "paypal" }
3204
3989
  );
3205
3990
  }
3206
3991
  const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
3207
3992
  if (error) {
3208
3993
  throw Object.assign(
3209
- new import_shared7.FloPayError(
3994
+ new import_shared8.FloPayError(
3210
3995
  error.message ?? "Failed to retrieve PayPal payment status.",
3211
3996
  "api_error",
3212
3997
  { code: error.code }
@@ -3217,14 +4002,14 @@ function FloPayCheckout({
3217
4002
  const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
3218
4003
  if (!paymentIntent || resultStatus === "failed") {
3219
4004
  throw Object.assign(
3220
- new import_shared7.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
4005
+ new import_shared8.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
3221
4006
  { checkoutMethod: "paypal" }
3222
4007
  );
3223
4008
  }
3224
4009
  const paymentMethodId = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
3225
4010
  let finalResultStatus = resultStatus;
3226
4011
  if (resumeState.sessionId) {
3227
- const resumeApi = new import_js3.PaymentAPI(resolvedBillingUrl);
4012
+ const resumeApi = new import_js4.PaymentAPI(resolvedBillingUrl);
3228
4013
  const resumeSessionResult = await resumeApi.getUnifiedCheckoutSession(resumeState.sessionId);
3229
4014
  const resumeSession = resumeSessionResult.data.session;
3230
4015
  if (resumeSession && resumeSession.status !== "complete") {
@@ -3241,7 +4026,7 @@ function FloPayCheckout({
3241
4026
  });
3242
4027
  if (processResult.type !== "success") {
3243
4028
  throw Object.assign(
3244
- new import_shared7.FloPayError("Failed to finalize PayPal payment.", "api_error"),
4029
+ new import_shared8.FloPayError("Failed to finalize PayPal payment.", "api_error"),
3245
4030
  { checkoutMethod: "paypal" }
3246
4031
  );
3247
4032
  }
@@ -3278,7 +4063,7 @@ function FloPayCheckout({
3278
4063
  }
3279
4064
  })();
3280
4065
  }, [emitDecline, locale, normalizeSavedPaymentError, resolvedBillingUrl]);
3281
- const initializedHashRef = (0, import_react8.useRef)(null);
4066
+ const initializedHashRef = (0, import_react9.useRef)(null);
3282
4067
  function hashCreateParams(params) {
3283
4068
  const key = JSON.stringify({
3284
4069
  c: params?.clientId,
@@ -3303,23 +4088,23 @@ function FloPayCheckout({
3303
4088
  }
3304
4089
  return `flopay_session_${Math.abs(h).toString(36)}`;
3305
4090
  }
3306
- const createSessionHash = (0, import_react8.useMemo)(
4091
+ const createSessionHash = (0, import_react9.useMemo)(
3307
4092
  () => effectiveCreateSession ? hashCreateParams(effectiveCreateSession) : "",
3308
4093
  [effectiveCreateSession]
3309
4094
  );
3310
- const createSessionParamsRef = (0, import_react8.useRef)(effectiveCreateSession);
4095
+ const createSessionParamsRef = (0, import_react9.useRef)(effectiveCreateSession);
3311
4096
  createSessionParamsRef.current = effectiveCreateSession;
3312
- (0, import_react8.useEffect)(() => {
4097
+ (0, import_react9.useEffect)(() => {
3313
4098
  setResolvedSessionId(sessionIdProp ?? "");
3314
4099
  }, [sessionIdProp]);
3315
- (0, import_react8.useEffect)(() => {
4100
+ (0, import_react9.useEffect)(() => {
3316
4101
  autoCheckoutAttempted.current = false;
3317
4102
  setModeError(initialErrorMessage);
3318
4103
  setModeOverlayError(null);
3319
4104
  setModeOverlayStatus(null);
3320
4105
  }, [createSessionHash, initialErrorMessage, sessionIdProp]);
3321
4106
  async function resolveInlineSession(params, cacheKey) {
3322
- const api = new import_js3.PaymentAPI(resolvedBillingUrl);
4107
+ const api = new import_js4.PaymentAPI(resolvedBillingUrl);
3323
4108
  let sid = typeof window !== "undefined" ? window.sessionStorage.getItem(cacheKey) : null;
3324
4109
  let realResult = null;
3325
4110
  if (sid) {
@@ -3355,11 +4140,11 @@ function FloPayCheckout({
3355
4140
  }
3356
4141
  return { sid: sid ?? "", result: realResult };
3357
4142
  }
3358
- const bootstrapInlineSession = (0, import_react8.useCallback)(
4143
+ const bootstrapInlineSession = (0, import_react9.useCallback)(
3359
4144
  async (patch) => {
3360
4145
  const baseParams = createSessionParamsRef.current;
3361
4146
  if (!baseParams) {
3362
- throw new import_shared7.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
4147
+ throw new import_shared8.FloPayError("createSession is required to bootstrap checkout.", "validation_error");
3363
4148
  }
3364
4149
  const mergedParams = mergeInlineSessionPatch(baseParams, patch);
3365
4150
  const cacheKey = hashCreateParams(mergedParams);
@@ -3416,7 +4201,7 @@ function FloPayCheckout({
3416
4201
  },
3417
4202
  [locale, resolvedBillingUrl]
3418
4203
  );
3419
- const handleInlineSessionPatch = (0, import_react8.useCallback)(async (patch) => {
4204
+ const handleInlineSessionPatch = (0, import_react9.useCallback)(async (patch) => {
3420
4205
  if (!hasInlineSessionPatchData(patch) || cardBootstrapPending) {
3421
4206
  return {
3422
4207
  sessionId: resolvedSessionId,
@@ -3439,7 +4224,7 @@ function FloPayCheckout({
3439
4224
  resolvedSessionId,
3440
4225
  session
3441
4226
  ]);
3442
- (0, import_react8.useEffect)(() => {
4227
+ (0, import_react9.useEffect)(() => {
3443
4228
  let cancelled = false;
3444
4229
  setLoadError(null);
3445
4230
  if (createSessionHash) {
@@ -3464,7 +4249,8 @@ function FloPayCheckout({
3464
4249
  const resolved = await bootstrapInlineSession();
3465
4250
  const resolvedSession = resolved.result.data.session ?? null;
3466
4251
  savedPaymentKeysRef.current = resolveSavedPaymentPublishableKeys(resolved.result);
3467
- if (!cancelled && shouldAutoProcessInlineSession && resolvedSession) {
4252
+ const resolvedPaypalOnly = isPayPalOnlyUnified(resolved.result);
4253
+ if (!cancelled && shouldAutoProcessInlineSession && resolvedSession && !resolvedPaypalOnly) {
3468
4254
  autoCheckoutAttempted.current = true;
3469
4255
  await runSavedPaymentFlow(resolvedSession, {
3470
4256
  attempt3DS: true,
@@ -3478,12 +4264,15 @@ function FloPayCheckout({
3478
4264
  return;
3479
4265
  }
3480
4266
  if (!cancelled && shouldAutoProcessInlineSession) {
4267
+ if (resolvedPaypalOnly) {
4268
+ autoCheckoutAttempted.current = true;
4269
+ }
3481
4270
  setModeOverlayStatus(null);
3482
4271
  setModeOverlayError(null);
3483
4272
  }
3484
4273
  } catch (err) {
3485
4274
  if (cancelled) return;
3486
- const errorCode = err instanceof import_shared7.FloPayError ? err.code : typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
4275
+ const errorCode = err instanceof import_shared8.FloPayError ? err.code : typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
3487
4276
  if (shouldAutoProcessInlineSession && errorCode === "session_auto_completed") {
3488
4277
  autoCheckoutAttempted.current = true;
3489
4278
  setModeOverlayStatus("success");
@@ -3499,7 +4288,7 @@ function FloPayCheckout({
3499
4288
  setModeOverlayStatus(null);
3500
4289
  setModeOverlayError(null);
3501
4290
  }
3502
- const floPayErr = err instanceof import_shared7.FloPayError ? err : new import_shared7.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
4291
+ const floPayErr = err instanceof import_shared8.FloPayError ? err : new import_shared8.FloPayError(err instanceof Error ? err.message : "Failed to create session", "api_error");
3503
4292
  setLoadError(floPayErr);
3504
4293
  }
3505
4294
  })();
@@ -3510,14 +4299,14 @@ function FloPayCheckout({
3510
4299
  setIsLoading(true);
3511
4300
  async function init() {
3512
4301
  try {
3513
- const api = new import_js3.PaymentAPI(resolvedBillingUrl);
4302
+ const api = new import_js4.PaymentAPI(resolvedBillingUrl);
3514
4303
  const result = await api.getUnifiedCheckoutSession(activeSessionId);
3515
4304
  if (cancelled) return;
3516
4305
  setUnified(result);
3517
4306
  const sess = result.data.session ?? null;
3518
4307
  setSession(sess);
3519
4308
  if (!sess) {
3520
- throw new import_shared7.FloPayError("No session data returned", "api_error");
4309
+ throw new import_shared8.FloPayError("No session data returned", "api_error");
3521
4310
  }
3522
4311
  if (sess.status === "complete") {
3523
4312
  setIsLoading(false);
@@ -3525,14 +4314,15 @@ function FloPayCheckout({
3525
4314
  return;
3526
4315
  }
3527
4316
  if (sess.status === "expired") {
3528
- throw new import_shared7.FloPayError("Checkout session has expired.", "api_error", {
4317
+ throw new import_shared8.FloPayError("Checkout session has expired.", "api_error", {
3529
4318
  code: "checkout_session_expired"
3530
4319
  });
3531
4320
  }
3532
4321
  const effectiveMode = checkoutModeProp ?? sess.checkoutMode ?? "full";
3533
4322
  setCurrentMode(effectiveMode);
3534
4323
  const hasPayPalRedirectParams = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent");
3535
- if (effectiveMode === "auto" && !autoCheckoutAttempted.current && !hasPayPalRedirectParams) {
4324
+ const paypalOnly = isPayPalOnlyUnified(result);
4325
+ if (effectiveMode === "auto" && !autoCheckoutAttempted.current && !hasPayPalRedirectParams && !paypalOnly) {
3536
4326
  autoCheckoutAttempted.current = true;
3537
4327
  const stripeInitPromise = initStripe(result);
3538
4328
  try {
@@ -3559,7 +4349,7 @@ function FloPayCheckout({
3559
4349
  if (!cancelled) setIsLoading(false);
3560
4350
  } catch (err) {
3561
4351
  if (cancelled) return;
3562
- const floPayErr = err instanceof import_shared7.FloPayError ? err : new import_shared7.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
4352
+ const floPayErr = err instanceof import_shared8.FloPayError ? err : new import_shared8.FloPayError(err instanceof Error ? err.message : "Failed to initialize checkout", "api_error");
3563
4353
  setLoadError(floPayErr);
3564
4354
  setIsLoading(false);
3565
4355
  }
@@ -3599,7 +4389,7 @@ function FloPayCheckout({
3599
4389
  initSessionDependency,
3600
4390
  runSavedPaymentFlow
3601
4391
  ]);
3602
- const handleConfirmCheckout = (0, import_react8.useCallback)(async () => {
4392
+ const handleConfirmCheckout = (0, import_react9.useCallback)(async () => {
3603
4393
  if (confirmProcessing || !session) return;
3604
4394
  setConfirmProcessing(true);
3605
4395
  setModeError(null);
@@ -3612,17 +4402,19 @@ function FloPayCheckout({
3612
4402
  setConfirmProcessing(false);
3613
4403
  }
3614
4404
  }, [activeSessionId, confirmProcessing, runSavedPaymentFlow, session]);
3615
- const providerOptions = (0, import_react8.useMemo)(() => {
3616
- if (!unified || !session) return void 0;
4405
+ const directPaypalConfig = resolveDirectPaypalConfig(unified);
4406
+ const isPaypalOnlySession = isPayPalOnlyUnified(unified);
4407
+ const providerOptions = (0, import_react9.useMemo)(() => {
4408
+ if (!unified || !session || !unified.data.stripe?.publishableKey) return void 0;
3617
4409
  const opts = {
3618
4410
  appearance,
3619
4411
  paymentMethodCreation: "manual",
3620
4412
  billingApiUrl: resolvedBillingUrl
3621
4413
  };
3622
- if (unified.provider === "stripe" && unified.data.stripe?.clientSecret) {
4414
+ if (unified.data.stripe?.clientSecret) {
3623
4415
  opts.clientSecret = unified.data.stripe.clientSecret;
3624
4416
  } else {
3625
- const displayTotal = (0, import_shared7.buildCheckoutDisplayData)(session).total;
4417
+ const displayTotal = (0, import_shared8.buildCheckoutDisplayData)(session).total;
3626
4418
  opts.amount = Math.round(displayTotal * 100) || session.amount;
3627
4419
  opts.currency = session.currency?.toLowerCase();
3628
4420
  }
@@ -3631,7 +4423,7 @@ function FloPayCheckout({
3631
4423
  const shouldHandleInlineSessionPatch = Boolean(
3632
4424
  createSessionParams && !children && layout === "buttons" && onBeforeButtonClick && effectiveCreateSessionMode === "full"
3633
4425
  );
3634
- const checkoutValue = (0, import_react8.useMemo)(
4426
+ const checkoutValue = (0, import_react9.useMemo)(
3635
4427
  () => ({
3636
4428
  session,
3637
4429
  loading: isLoading,
@@ -3652,8 +4444,8 @@ function FloPayCheckout({
3652
4444
  cardBootstrapPending
3653
4445
  ]
3654
4446
  );
3655
- const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
3656
- const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4447
+ const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && !isPaypalOnlySession && (!flopay || !providerOptions);
4448
+ const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3657
4449
  ProcessingOverlay,
3658
4450
  {
3659
4451
  status: modeOverlayStatus,
@@ -3662,31 +4454,31 @@ function FloPayCheckout({
3662
4454
  ) : null;
3663
4455
  if (isLoading) {
3664
4456
  if (loadingNode) {
3665
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
4457
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3666
4458
  loadingNode,
3667
4459
  modeOverlay
3668
4460
  ] });
3669
4461
  }
3670
4462
  if (layout === "buttons") {
3671
- const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
4463
+ const skeletonBar = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3672
4464
  height: h,
3673
4465
  borderRadius: 8,
3674
4466
  background: "#e5e7eb",
3675
4467
  animation: "flopay-loading-pulse 1.5s ease-in-out infinite"
3676
4468
  } });
3677
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3678
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
4469
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4470
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
3679
4471
  showPayPal && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
3680
4472
  (showApplePay || showGooglePay) && skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
3681
4473
  skeletonBar(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
3682
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
4474
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-loading-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
3683
4475
  ] }),
3684
4476
  modeOverlay
3685
4477
  ] });
3686
4478
  }
3687
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3688
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
3689
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
4479
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4480
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", justifyContent: "center", padding: 32 }, children: [
4481
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3690
4482
  width: 24,
3691
4483
  height: 24,
3692
4484
  border: "2px solid #e5e7eb",
@@ -3694,16 +4486,16 @@ function FloPayCheckout({
3694
4486
  borderRadius: "50%",
3695
4487
  animation: "spin 0.6s linear infinite"
3696
4488
  } }),
3697
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
4489
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
3698
4490
  ] }),
3699
4491
  modeOverlay
3700
4492
  ] });
3701
4493
  }
3702
4494
  if (loadError) {
3703
4495
  if (errorNode) {
3704
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
4496
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: errorNode(loadError) });
3705
4497
  }
3706
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4498
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3707
4499
  "div",
3708
4500
  {
3709
4501
  style: {
@@ -3717,8 +4509,8 @@ function FloPayCheckout({
3717
4509
  ) });
3718
4510
  }
3719
4511
  if (shouldShowInterimButtons) {
3720
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3721
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4512
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4513
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3722
4514
  InterimButtonsView,
3723
4515
  {
3724
4516
  onButtonClick,
@@ -3735,13 +4527,55 @@ function FloPayCheckout({
3735
4527
  modeOverlay
3736
4528
  ] });
3737
4529
  }
4530
+ if (isPaypalOnlySession && session && directPaypalConfig) {
4531
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4532
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
4533
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4534
+ "div",
4535
+ {
4536
+ role: "alert",
4537
+ "data-testid": "flopay-error",
4538
+ style: {
4539
+ padding: "0.625rem 0.875rem",
4540
+ background: "#FEF2F2",
4541
+ border: "1px solid #FECACA",
4542
+ borderRadius: "8px",
4543
+ color: "#991B1B",
4544
+ fontSize: "0.85rem",
4545
+ fontWeight: 600
4546
+ },
4547
+ children: modeError
4548
+ }
4549
+ ),
4550
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4551
+ DirectPayPalButton,
4552
+ {
4553
+ sessionId: activeSessionId,
4554
+ billingApiUrl: resolvedBillingUrl,
4555
+ email: session.customer?.email,
4556
+ clientId: directPaypalConfig.clientId,
4557
+ environment: directPaypalConfig.environment,
4558
+ currency: (session.currency ?? "usd").toUpperCase(),
4559
+ isSubscription: session.mode === "subscription",
4560
+ onComplete,
4561
+ onErrorChange: setModeError,
4562
+ onDecline,
4563
+ onButtonClick,
4564
+ session,
4565
+ debug
4566
+ }
4567
+ )
4568
+ ] }) }),
4569
+ modeOverlay
4570
+ ] });
4571
+ }
3738
4572
  if (!flopay || !providerOptions) {
3739
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: modeOverlay });
4573
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: modeOverlay });
3740
4574
  }
3741
4575
  if (currentMode === "confirm") {
3742
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3743
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, children: [
3744
- modeError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4576
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4577
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className, children: [
4578
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3745
4579
  "div",
3746
4580
  {
3747
4581
  style: {
@@ -3756,7 +4590,7 @@ function FloPayCheckout({
3756
4590
  renderConfirmButton ? renderConfirmButton({
3757
4591
  onConfirm: handleConfirmCheckout,
3758
4592
  isProcessing: confirmProcessing
3759
- }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4593
+ }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3760
4594
  "button",
3761
4595
  {
3762
4596
  type: "button",
@@ -3781,9 +4615,9 @@ function FloPayCheckout({
3781
4615
  modeOverlay
3782
4616
  ] });
3783
4617
  }
3784
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3785
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3786
- modeError && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4618
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4619
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(FloPayProvider, { flopay, paypalFlopay, options: providerOptions, children: children ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4620
+ modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3787
4621
  "div",
3788
4622
  {
3789
4623
  style: {
@@ -3798,7 +4632,7 @@ function FloPayCheckout({
3798
4632
  children: modeError
3799
4633
  }
3800
4634
  ),
3801
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4635
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3802
4636
  SessionInjector,
3803
4637
  {
3804
4638
  sessionId: activeSessionId,
@@ -3807,7 +4641,7 @@ function FloPayCheckout({
3807
4641
  children
3808
4642
  }
3809
4643
  )
3810
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4644
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3811
4645
  SplitCardForm,
3812
4646
  {
3813
4647
  sessionId: activeSessionId,
@@ -3815,7 +4649,7 @@ function FloPayCheckout({
3815
4649
  userId: session?.customer?.id,
3816
4650
  firstName: session?.customer?.firstName,
3817
4651
  lastName: session?.customer?.lastName,
3818
- totalAmount: session ? Math.round((0, import_shared7.buildCheckoutDisplayData)(session).total * 100) : 0,
4652
+ totalAmount: session ? Math.round((0, import_shared8.buildCheckoutDisplayData)(session).total * 100) : 0,
3819
4653
  currency: session?.currency?.toLowerCase() ?? "usd",
3820
4654
  onComplete,
3821
4655
  onError,
@@ -3846,7 +4680,11 @@ function FloPayCheckout({
3846
4680
  checkoutType: createSessionParams ? "embedded_checkout" : "standard_checkout",
3847
4681
  checkoutLayout: children ? "custom_layout" : layout === "buttons" ? "buttons_layout" : "default_layout",
3848
4682
  submitLabel,
3849
- className
4683
+ className,
4684
+ directPaypal: resolveDirectPaypalConfig(unified),
4685
+ isSubscription: session?.mode === "subscription",
4686
+ session,
4687
+ debug
3850
4688
  }
3851
4689
  ) }) }),
3852
4690
  modeOverlay
@@ -3858,8 +4696,8 @@ function SessionInjector({
3858
4696
  session,
3859
4697
  children
3860
4698
  }) {
3861
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: import_react8.default.Children.map(children, (child) => {
3862
- if (!import_react8.default.isValidElement(child)) return child;
4699
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: import_react9.default.Children.map(children, (child) => {
4700
+ if (!import_react9.default.isValidElement(child)) return child;
3863
4701
  const existing = child.props;
3864
4702
  const injected = {};
3865
4703
  if (!existing.sessionId) injected.sessionId = sessionId;
@@ -3873,7 +4711,7 @@ function SessionInjector({
3873
4711
  injected.lastName = session.customer.lastName;
3874
4712
  }
3875
4713
  if (Object.keys(injected).length === 0) return child;
3876
- return import_react8.default.cloneElement(child, injected);
4714
+ return import_react9.default.cloneElement(child, injected);
3877
4715
  }) });
3878
4716
  }
3879
4717
  function InterimButtonsView({
@@ -3891,15 +4729,15 @@ function InterimButtonsView({
3891
4729
  cardBackButtonContent,
3892
4730
  cardTitleContent
3893
4731
  }) {
3894
- const [showCardForm, setShowCardForm] = (0, import_react8.useState)(false);
4732
+ const [showCardForm, setShowCardForm] = (0, import_react9.useState)(false);
3895
4733
  const isCardOpenControlled = typeof cardOpen === "boolean";
3896
- (0, import_react8.useEffect)(() => {
4734
+ (0, import_react9.useEffect)(() => {
3897
4735
  if (isCardOpenControlled) {
3898
4736
  setShowCardForm(cardOpen);
3899
4737
  }
3900
4738
  }, [cardOpen, isCardOpenControlled]);
3901
- const bStyles = (0, import_react8.useMemo)(() => {
3902
- const base = (0, import_shared7.resolveButtonsLayoutTheme)(buttonsTheme);
4739
+ const bStyles = (0, import_react9.useMemo)(() => {
4740
+ const base = (0, import_shared8.resolveButtonsLayoutTheme)(buttonsTheme);
3903
4741
  if (!stylesOverride) return base;
3904
4742
  return {
3905
4743
  ...base,
@@ -3912,7 +4750,7 @@ function InterimButtonsView({
3912
4750
  title: { ...base.title, ...stylesOverride.title }
3913
4751
  };
3914
4752
  }, [buttonsTheme, stylesOverride]);
3915
- const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
4753
+ const skeleton = (h) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3916
4754
  height: h,
3917
4755
  borderRadius: 8,
3918
4756
  background: "#e5e7eb",
@@ -3924,15 +4762,15 @@ function InterimButtonsView({
3924
4762
  const inputBg = bStyles.cardInputBackground ?? "white";
3925
4763
  const hideBackButtonLabel = isEmptySlotContent(cardBackButtonContent);
3926
4764
  const hideTitle = isEmptySlotContent(cardTitleContent);
3927
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
4765
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: {
3928
4766
  backgroundColor: bStyles.cardFormContainer?.backgroundColor ?? "white",
3929
4767
  borderRadius: "8px",
3930
4768
  animation: "flopay-interim-expand 0.35s cubic-bezier(0.4, 0, 0.2, 1) both",
3931
4769
  overflow: "hidden",
3932
4770
  ...bStyles.cardFormContainer
3933
4771
  }, children: [
3934
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
3935
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4772
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", padding: "0.75rem 0 0.625rem" }, children: [
4773
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3936
4774
  "button",
3937
4775
  {
3938
4776
  type: "button",
@@ -3959,7 +4797,7 @@ function InterimButtonsView({
3959
4797
  ...bStyles.backButton
3960
4798
  },
3961
4799
  children: [
3962
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: {
4800
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: {
3963
4801
  display: "inline-flex",
3964
4802
  alignItems: "center",
3965
4803
  justifyContent: "center",
@@ -3968,12 +4806,12 @@ function InterimButtonsView({
3968
4806
  borderRadius: "50%",
3969
4807
  backgroundColor: "#f3f4f6",
3970
4808
  ...bStyles.backButtonIcon
3971
- }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
3972
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
4809
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M15 18l-6-6 6-6" }) }) }),
4810
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BackButtonContentSlot, { content: cardBackButtonContent })
3973
4811
  ]
3974
4812
  }
3975
4813
  ),
3976
- hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
4814
+ hideTitle ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1 } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3977
4815
  flex: 1,
3978
4816
  textAlign: "center",
3979
4817
  fontWeight: 600,
@@ -3981,15 +4819,15 @@ function InterimButtonsView({
3981
4819
  color: "#262833",
3982
4820
  paddingRight: 80,
3983
4821
  ...bStyles.title
3984
- }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TitleContentSlot, { content: cardTitleContent }) })
4822
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TitleContentSlot, { content: cardTitleContent }) })
3985
4823
  ] }),
3986
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
3987
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex" }, children: [
3988
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderRight: "none", borderBottomLeftRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
3989
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderBottomRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
4824
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTopLeftRadius: 8, borderTopRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "60%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
4825
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex" }, children: [
4826
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderRight: "none", borderBottomLeftRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "50%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
4827
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1, backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderTop: "none", borderBottomRightRadius: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "40%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) })
3990
4828
  ] }),
3991
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
3992
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: {
4829
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { backgroundColor: inputBg, border: `1px solid ${inputBorder}`, borderRadius: 8, marginTop: 8, padding: 12, height: 45 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { width: "45%", height: 14, borderRadius: 4, background: "#e5e7eb", animation: "flopay-interim-pulse 1.5s ease-in-out infinite" } }) }),
4830
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
3993
4831
  height: 50,
3994
4832
  borderRadius: 8,
3995
4833
  marginTop: 16,
@@ -3998,7 +4836,7 @@ function InterimButtonsView({
3998
4836
  ...bStyles.submitButton,
3999
4837
  opacity: 0.5
4000
4838
  } }),
4001
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `
4839
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
4002
4840
  @keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
4003
4841
  @keyframes flopay-interim-expand {
4004
4842
  0% { opacity: 0; max-height: 0; transform: translateY(-12px); }
@@ -4008,10 +4846,10 @@ function InterimButtonsView({
4008
4846
  ` })
4009
4847
  ] });
4010
4848
  }
4011
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
4849
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
4012
4850
  showPayPal && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
4013
4851
  (showApplePay || showGooglePay) && skeleton(DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT2),
4014
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4852
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4015
4853
  "button",
4016
4854
  {
4017
4855
  type: "button",
@@ -4051,10 +4889,10 @@ function InterimButtonsView({
4051
4889
  onMouseUp: (e) => {
4052
4890
  e.currentTarget.style.transform = "scale(1)";
4053
4891
  },
4054
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardButtonContentSlot, { content: cardButtonContent })
4892
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardButtonContentSlot, { content: cardButtonContent })
4055
4893
  }
4056
4894
  ),
4057
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: {
4895
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: {
4058
4896
  margin: "0.25rem 0",
4059
4897
  padding: "0.625rem 0.875rem",
4060
4898
  background: "#FEF2F2",
@@ -4068,22 +4906,22 @@ function InterimButtonsView({
4068
4906
  gap: "0.5rem",
4069
4907
  ...bStyles.errorBanner
4070
4908
  }, children: [
4071
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
4909
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 9v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z", stroke: "#DC2626", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
4072
4910
  errorMessage
4073
4911
  ] }),
4074
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
4912
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes flopay-interim-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }` })
4075
4913
  ] });
4076
4914
  }
4077
4915
 
4078
4916
  // src/checkout-form.tsx
4079
- var import_js4 = require("@flopay/js");
4080
- var import_shared8 = require("@flopay/shared");
4081
- var import_react9 = require("react");
4082
- var import_jsx_runtime7 = require("react/jsx-runtime");
4917
+ var import_js5 = require("@flopay/js");
4918
+ var import_shared9 = require("@flopay/shared");
4919
+ var import_react10 = require("react");
4920
+ var import_jsx_runtime8 = require("react/jsx-runtime");
4083
4921
  var WALLET_RESUME_KEY2 = "flopay_wallet_resume";
4084
- var CheckoutForm = (0, import_react9.forwardRef)(
4922
+ var CheckoutForm = (0, import_react10.forwardRef)(
4085
4923
  function CheckoutForm2(props, ref) {
4086
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
4924
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckoutFormInner, { ...props, innerRef: ref });
4087
4925
  }
4088
4926
  );
4089
4927
  function CheckoutFormInner({
@@ -4112,34 +4950,34 @@ function CheckoutFormInner({
4112
4950
  const paypalFlopay = usePayPalFloPay();
4113
4951
  const elements = useElements();
4114
4952
  const contextBillingUrl = useBillingApiUrl();
4115
- const [processing, setProcessing] = (0, import_react9.useState)(false);
4116
- const [error, setError] = (0, import_react9.useState)(null);
4117
- const [is3DSActive, setIs3DSActive] = (0, import_react9.useState)(false);
4953
+ const [processing, setProcessing] = (0, import_react10.useState)(false);
4954
+ const [error, setError] = (0, import_react10.useState)(null);
4955
+ const [is3DSActive, setIs3DSActive] = (0, import_react10.useState)(false);
4118
4956
  const displayError = externalError ?? error;
4119
4957
  const isSubmitting = externalProcessing ?? processing;
4120
4958
  const isSelfContained = !onTokenizedBody;
4121
4959
  const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
4122
- const updateError = (0, import_react9.useCallback)(
4960
+ const updateError = (0, import_react10.useCallback)(
4123
4961
  (err) => {
4124
4962
  setError(err);
4125
4963
  onErrorChange?.(err);
4126
4964
  },
4127
4965
  [onErrorChange]
4128
4966
  );
4129
- const emitDecline = (0, import_react9.useCallback)(
4967
+ const emitDecline = (0, import_react10.useCallback)(
4130
4968
  (input, overrides) => {
4131
4969
  onDecline?.(buildDeclineEvent("card", input, overrides));
4132
4970
  },
4133
4971
  [onDecline]
4134
4972
  );
4135
- const processPaymentInternal = (0, import_react9.useCallback)(
4973
+ const processPaymentInternal = (0, import_react10.useCallback)(
4136
4974
  async (tokenizedBody, completionPaymentMethodId) => {
4137
4975
  setProcessing(true);
4138
4976
  updateError(null);
4139
4977
  const resolvedCompletionPaymentMethodId = completionPaymentMethodId ?? resolveTokenizedPaymentMethodId(tokenizedBody);
4140
4978
  const requestTokenizedBody = tokenizedBody.originalPaymentMethodId ? { ...tokenizedBody, originalPaymentMethodId: void 0 } : tokenizedBody;
4141
4979
  try {
4142
- const api = new import_js4.PaymentAPI(baseUrl);
4980
+ const api = new import_js5.PaymentAPI(baseUrl);
4143
4981
  const response = await api.processPayment(userId ?? "", {
4144
4982
  sessionId,
4145
4983
  tokenizedData: requestTokenizedBody,
@@ -4243,7 +5081,7 @@ function CheckoutFormInner({
4243
5081
  },
4244
5082
  [baseUrl, sessionId, userId, email, firstName, lastName, chv, flopay, paypalFlopay, onComplete, onError, onDecline, updateError, emitDecline]
4245
5083
  );
4246
- const dispatchTokenizedBody = (0, import_react9.useCallback)(
5084
+ const dispatchTokenizedBody = (0, import_react10.useCallback)(
4247
5085
  (tokenizedBody) => {
4248
5086
  if (onTokenizedBody) {
4249
5087
  onTokenizedBody(tokenizedBody);
@@ -4253,7 +5091,7 @@ function CheckoutFormInner({
4253
5091
  },
4254
5092
  [onTokenizedBody, processPaymentInternal]
4255
5093
  );
4256
- (0, import_react9.useImperativeHandle)(innerRef, () => ({
5094
+ (0, import_react10.useImperativeHandle)(innerRef, () => ({
4257
5095
  async handleNextAction(secret) {
4258
5096
  if (!flopay) return;
4259
5097
  setIs3DSActive(true);
@@ -4280,7 +5118,7 @@ function CheckoutFormInner({
4280
5118
  }
4281
5119
  }
4282
5120
  }), [flopay, dispatchTokenizedBody, onError, updateError, emitDecline]);
4283
- (0, import_react9.useEffect)(() => {
5121
+ (0, import_react10.useEffect)(() => {
4284
5122
  if (typeof window === "undefined") return;
4285
5123
  const stored = localStorage.getItem(WALLET_RESUME_KEY2);
4286
5124
  if (!stored) return;
@@ -4298,7 +5136,7 @@ function CheckoutFormInner({
4298
5136
  localStorage.removeItem(WALLET_RESUME_KEY2);
4299
5137
  }
4300
5138
  }, [sessionId, dispatchTokenizedBody]);
4301
- const handleSubmit = (0, import_react9.useCallback)(
5139
+ const handleSubmit = (0, import_react10.useCallback)(
4302
5140
  async (e) => {
4303
5141
  e.preventDefault();
4304
5142
  if (!flopay || !elements || isSubmitting) return;
@@ -4322,7 +5160,7 @@ function CheckoutFormInner({
4322
5160
  return;
4323
5161
  }
4324
5162
  if (!sessionId || !email) {
4325
- throw new import_shared8.FloPayError("Missing sessionId or email", "validation_error");
5163
+ throw new import_shared9.FloPayError("Missing sessionId or email", "validation_error");
4326
5164
  }
4327
5165
  const intentResponse = await fetch(`${baseUrl}/v1/checkouts/payments/intents`, {
4328
5166
  method: "POST",
@@ -4346,7 +5184,7 @@ function CheckoutFormInner({
4346
5184
  }
4347
5185
  const intentJson = await intentResponse.json();
4348
5186
  const intentClientSecret = intentJson.data?.id;
4349
- if (!intentClientSecret) throw new import_shared8.FloPayError("No client_secret in payment intent response", "api_error");
5187
+ if (!intentClientSecret) throw new import_shared9.FloPayError("No client_secret in payment intent response", "api_error");
4350
5188
  const confirmResult = await flopay.confirmCardPayment({
4351
5189
  clientSecret: intentClientSecret,
4352
5190
  paymentMethodId: pmResult.paymentMethodId
@@ -4365,7 +5203,7 @@ function CheckoutFormInner({
4365
5203
  const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
4366
5204
  const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
4367
5205
  if (!paymentIntentId) {
4368
- const error2 = new import_shared8.FloPayError("No payment intent returned after confirmation.", "api_error");
5206
+ const error2 = new import_shared9.FloPayError("No payment intent returned after confirmation.", "api_error");
4369
5207
  updateError(error2.message);
4370
5208
  onError?.(error2);
4371
5209
  return;
@@ -4388,8 +5226,8 @@ function CheckoutFormInner({
4388
5226
  [flopay, elements, isSubmitting, sessionId, email, baseUrl, isSelfContained, dispatchTokenizedBody, onError, updateError, emitDecline]
4389
5227
  );
4390
5228
  const isReady = flopay !== null && elements !== null;
4391
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
4392
- (is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-testid": "flopay-overlay", style: {
5229
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("form", { onSubmit: handleSubmit, className, style: { position: "relative" }, children: [
5230
+ (is3DSActive || isSubmitting) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-testid": "flopay-overlay", style: {
4393
5231
  position: "absolute",
4394
5232
  inset: 0,
4395
5233
  background: "rgba(255,255,255,0.7)",
@@ -4398,12 +5236,12 @@ function CheckoutFormInner({
4398
5236
  justifyContent: "center",
4399
5237
  zIndex: 10
4400
5238
  }, children: is3DSActive ? "Verifying payment..." : "Processing..." }),
4401
- !isReady && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
4402
- isReady && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
4403
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PaymentElement, { options: { layout } }),
4404
- showAddress && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
4405
- displayError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
4406
- children ?? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5239
+ !isReady && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { "data-testid": "flopay-loading", "aria-busy": "true", children: "Loading payment form..." }),
5240
+ isReady && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
5241
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaymentElement, { options: { layout } }),
5242
+ showAddress && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AddressElement, { options: { mode: showAddress === true ? "billing" : showAddress } }),
5243
+ displayError && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { role: "alert", "data-testid": "flopay-error", style: { color: "red", margin: "0.75rem 0" }, children: displayError }),
5244
+ children ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4407
5245
  "button",
4408
5246
  {
4409
5247
  type: "submit",
@@ -4417,10 +5255,10 @@ function CheckoutFormInner({
4417
5255
  }
4418
5256
 
4419
5257
  // src/paypal-button.tsx
4420
- var import_js5 = require("@flopay/js");
4421
- var import_shared9 = require("@flopay/shared");
4422
- var import_react10 = require("react");
4423
- var import_jsx_runtime8 = require("react/jsx-runtime");
5258
+ var import_js6 = require("@flopay/js");
5259
+ var import_shared10 = require("@flopay/shared");
5260
+ var import_react11 = require("react");
5261
+ var import_jsx_runtime9 = require("react/jsx-runtime");
4424
5262
  function PayPalButton({
4425
5263
  sessionId,
4426
5264
  billingApiUrl,
@@ -4437,14 +5275,14 @@ function PayPalButton({
4437
5275
  const flopay = useFloPay();
4438
5276
  const elements = useElements();
4439
5277
  const contextBillingUrl = useBillingApiUrl();
4440
- const [ready, setReady] = (0, import_react10.useState)(false);
4441
- const [submitting, setSubmitting] = (0, import_react10.useState)(false);
4442
- const paypalResumeAttempted = (0, import_react10.useRef)(false);
5278
+ const [ready, setReady] = (0, import_react11.useState)(false);
5279
+ const [submitting, setSubmitting] = (0, import_react11.useState)(false);
5280
+ const paypalResumeAttempted = (0, import_react11.useRef)(false);
4443
5281
  const baseUrl = (billingApiUrl || contextBillingUrl).replace(/\/+$/, "");
4444
- const processPaymentInternal = (0, import_react10.useCallback)(
5282
+ const processPaymentInternal = (0, import_react11.useCallback)(
4445
5283
  async (tokenizedBody) => {
4446
5284
  try {
4447
- const api = new import_js5.PaymentAPI(baseUrl);
5285
+ const api = new import_js6.PaymentAPI(baseUrl);
4448
5286
  const response = await api.processPayment(userId ?? "", {
4449
5287
  sessionId,
4450
5288
  tokenizedData: tokenizedBody,
@@ -4468,7 +5306,7 @@ function PayPalButton({
4468
5306
  },
4469
5307
  [baseUrl, sessionId, userId, email, firstName, lastName, chv, onComplete, onErrorChange]
4470
5308
  );
4471
- const dispatchTokenizedBody = (0, import_react10.useCallback)(
5309
+ const dispatchTokenizedBody = (0, import_react11.useCallback)(
4472
5310
  (body) => {
4473
5311
  if (onTokenizedBody) {
4474
5312
  onTokenizedBody(body);
@@ -4478,7 +5316,7 @@ function PayPalButton({
4478
5316
  },
4479
5317
  [onTokenizedBody, processPaymentInternal]
4480
5318
  );
4481
- (0, import_react10.useEffect)(() => {
5319
+ (0, import_react11.useEffect)(() => {
4482
5320
  if (!flopay || paypalResumeAttempted.current) return;
4483
5321
  const params = new URLSearchParams(window.location.search);
4484
5322
  const paymentIntentId = params.get("payment_intent");
@@ -4526,13 +5364,13 @@ function PayPalButton({
4526
5364
  }
4527
5365
  })();
4528
5366
  }, [flopay, dispatchTokenizedBody, onErrorChange]);
4529
- const handlePayPalConfirm = (0, import_react10.useCallback)(async () => {
5367
+ const handlePayPalConfirm = (0, import_react11.useCallback)(async () => {
4530
5368
  if (!flopay || !elements) return;
4531
5369
  try {
4532
5370
  setSubmitting(true);
4533
5371
  onErrorChange?.(null);
4534
5372
  if (!sessionId || !email) {
4535
- throw new import_shared9.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
5373
+ throw new import_shared10.FloPayError("Missing sessionId or email for PayPal payment", "validation_error");
4536
5374
  }
4537
5375
  const result = await flopay.confirmPayPalPayment({
4538
5376
  billingApiUrl: baseUrl,
@@ -4559,11 +5397,11 @@ function PayPalButton({
4559
5397
  }
4560
5398
  }, [flopay, elements, sessionId, email, baseUrl, dispatchTokenizedBody, onErrorChange]);
4561
5399
  if (!flopay || !elements) {
4562
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
5400
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6, animation: "pulse 1.5s infinite" } });
4563
5401
  }
4564
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
4565
- !ready && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
4566
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5402
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
5403
+ !ready && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { height: 45, background: "#f0f0f0", borderRadius: 6 } }),
5404
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: ready ? {} : { display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4567
5405
  "button",
4568
5406
  {
4569
5407
  type: "button",
@@ -4585,7 +5423,7 @@ function PayPalButton({
4585
5423
  children: submitting ? "Processing..." : "PayPal"
4586
5424
  }
4587
5425
  ) }),
4588
- (submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
5426
+ (submitting || isProcessing) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: {
4589
5427
  position: "fixed",
4590
5428
  inset: 0,
4591
5429
  background: "rgba(0,0,0,0.4)",
@@ -4593,7 +5431,7 @@ function PayPalButton({
4593
5431
  alignItems: "center",
4594
5432
  justifyContent: "center",
4595
5433
  zIndex: 1e3
4596
- }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: {
5434
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: {
4597
5435
  background: "white",
4598
5436
  borderRadius: 8,
4599
5437
  padding: "1.5rem",
@@ -4605,20 +5443,20 @@ function PayPalButton({
4605
5443
  }
4606
5444
 
4607
5445
  // src/automatic-payment-button.tsx
4608
- var import_react11 = require("react");
4609
- var import_js6 = require("@flopay/js");
4610
- var import_shared10 = require("@flopay/shared");
4611
- var import_jsx_runtime9 = require("react/jsx-runtime");
5446
+ var import_react12 = require("react");
5447
+ var import_js7 = require("@flopay/js");
5448
+ var import_shared11 = require("@flopay/shared");
5449
+ var import_jsx_runtime10 = require("react/jsx-runtime");
4612
5450
  var DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3 = 44;
4613
5451
  var PAYPAL_RESUME_STORAGE_KEY2 = "flopay_automatic_payment_button_resume";
4614
5452
  function sleep2(ms) {
4615
5453
  return new Promise((resolve) => setTimeout(resolve, ms));
4616
5454
  }
4617
5455
  function coerceError(err, fallbackMessage) {
4618
- if (err instanceof import_shared10.FloPayError) {
5456
+ if (err instanceof import_shared11.FloPayError) {
4619
5457
  return err;
4620
5458
  }
4621
- return new import_shared10.FloPayError(
5459
+ return new import_shared11.FloPayError(
4622
5460
  err instanceof Error ? err.message : fallbackMessage,
4623
5461
  "api_error"
4624
5462
  );
@@ -4725,11 +5563,11 @@ function FloPayAutomaticPaymentButton({
4725
5563
  style,
4726
5564
  ...buttonProps
4727
5565
  }) {
4728
- const resolvedBillingUrl = (0, import_react11.useMemo)(
4729
- () => (0, import_shared10.resolveBillingApiUrl)(billingApiUrl),
5566
+ const resolvedBillingUrl = (0, import_react12.useMemo)(
5567
+ () => (0, import_shared11.resolveBillingApiUrl)(billingApiUrl),
4730
5568
  [billingApiUrl]
4731
5569
  );
4732
- const createSessionDraft = (0, import_react11.useMemo)(
5570
+ const createSessionDraft = (0, import_react12.useMemo)(
4733
5571
  () => resolveCreateSessionDraft({
4734
5572
  createSession,
4735
5573
  clientId,
@@ -4755,43 +5593,47 @@ function FloPayAutomaticPaymentButton({
4755
5593
  utmMetadata
4756
5594
  ]
4757
5595
  );
4758
- const [isProcessing, setIsProcessing] = (0, import_react11.useState)(false);
4759
- const [overlayStatus, setOverlayStatus] = (0, import_react11.useState)(null);
4760
- const [overlayError, setOverlayError] = (0, import_react11.useState)(null);
4761
- const [fallbackSession, setFallbackSession] = (0, import_react11.useState)(null);
4762
- const automaticPaymentToken = (0, import_react11.useMemo)(
5596
+ const [isProcessing, setIsProcessing] = (0, import_react12.useState)(false);
5597
+ const [overlayStatus, setOverlayStatus] = (0, import_react12.useState)(null);
5598
+ const [overlayError, setOverlayError] = (0, import_react12.useState)(null);
5599
+ const [fallbackSession, setFallbackSession] = (0, import_react12.useState)(null);
5600
+ const automaticPaymentToken = (0, import_react12.useMemo)(
4763
5601
  () => paymentMethodId ? {
4764
5602
  id: paymentMethodId,
4765
- type: "card",
5603
+ // Saved PayPal `user_payment_method` records are submitted with
5604
+ // `type: 'paypal'` so the backend routes the upsell through the
5605
+ // direct PayPal gateway's vaulted-token flow. Card and wallet PMs
5606
+ // continue to use `type: 'card'`.
5607
+ type: checkoutMethod === "paypal" ? "paypal" : "card",
4766
5608
  ...checkoutMethod === "paypal" ? { isPaypal: true } : {}
4767
5609
  } : void 0,
4768
5610
  [checkoutMethod, paymentMethodId]
4769
5611
  );
4770
- const isMountedRef = (0, import_react11.useRef)(true);
4771
- const resumeAttemptedRef = (0, import_react11.useRef)(false);
4772
- const fallbackSessionRef = (0, import_react11.useRef)(fallbackSession);
4773
- const onSuccessRef = (0, import_react11.useRef)(onSuccess);
4774
- const onErrorRef = (0, import_react11.useRef)(onError);
4775
- const onDeclineRef = (0, import_react11.useRef)(onDecline);
4776
- (0, import_react11.useEffect)(() => {
5612
+ const isMountedRef = (0, import_react12.useRef)(true);
5613
+ const resumeAttemptedRef = (0, import_react12.useRef)(false);
5614
+ const fallbackSessionRef = (0, import_react12.useRef)(fallbackSession);
5615
+ const onSuccessRef = (0, import_react12.useRef)(onSuccess);
5616
+ const onErrorRef = (0, import_react12.useRef)(onError);
5617
+ const onDeclineRef = (0, import_react12.useRef)(onDecline);
5618
+ (0, import_react12.useEffect)(() => {
4777
5619
  fallbackSessionRef.current = fallbackSession;
4778
5620
  }, [fallbackSession]);
4779
- (0, import_react11.useEffect)(() => {
5621
+ (0, import_react12.useEffect)(() => {
4780
5622
  onSuccessRef.current = onSuccess;
4781
5623
  }, [onSuccess]);
4782
- (0, import_react11.useEffect)(() => {
5624
+ (0, import_react12.useEffect)(() => {
4783
5625
  onErrorRef.current = onError;
4784
5626
  }, [onError]);
4785
- (0, import_react11.useEffect)(() => {
5627
+ (0, import_react12.useEffect)(() => {
4786
5628
  onDeclineRef.current = onDecline;
4787
5629
  }, [onDecline]);
4788
- (0, import_react11.useEffect)(() => {
5630
+ (0, import_react12.useEffect)(() => {
4789
5631
  isMountedRef.current = true;
4790
5632
  return () => {
4791
5633
  isMountedRef.current = false;
4792
5634
  };
4793
5635
  }, []);
4794
- (0, import_react11.useEffect)(() => {
5636
+ (0, import_react12.useEffect)(() => {
4795
5637
  if (!fallbackSession || typeof window === "undefined") {
4796
5638
  return;
4797
5639
  }
@@ -4805,13 +5647,13 @@ function FloPayAutomaticPaymentButton({
4805
5647
  window.removeEventListener("keydown", handleKeyDown);
4806
5648
  };
4807
5649
  }, [fallbackSession]);
4808
- const emitDecline = (0, import_react11.useCallback)((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
5650
+ const emitDecline = (0, import_react12.useCallback)((error, method = DEFAULT_SAVED_PAYMENT_DECLINE_METHOD) => {
4809
5651
  onDeclineRef.current?.(buildDeclineEvent(method, error, {
4810
5652
  code: error.code,
4811
5653
  declineCode: error.declineCode
4812
5654
  }));
4813
5655
  }, []);
4814
- const showSuccess = (0, import_react11.useCallback)(async (event) => {
5656
+ const showSuccess = (0, import_react12.useCallback)(async (event) => {
4815
5657
  if (!isMountedRef.current) return;
4816
5658
  setOverlayError(null);
4817
5659
  setOverlayStatus("success");
@@ -4819,7 +5661,7 @@ function FloPayAutomaticPaymentButton({
4819
5661
  if (!isMountedRef.current) return;
4820
5662
  onSuccessRef.current?.(event);
4821
5663
  }, []);
4822
- const showError = (0, import_react11.useCallback)(async (error, options) => {
5664
+ const showError = (0, import_react12.useCallback)(async (error, options) => {
4823
5665
  if (!isMountedRef.current) return;
4824
5666
  onErrorRef.current?.(error);
4825
5667
  if (options?.emitDecline) {
@@ -4829,10 +5671,10 @@ function FloPayAutomaticPaymentButton({
4829
5671
  setOverlayStatus("error");
4830
5672
  await sleep2(PROCESSING_OVERLAY_ERROR_DELAY_MS);
4831
5673
  }, [emitDecline]);
4832
- const processResolvedSession = (0, import_react11.useCallback)(async (apiResult, resolvedSessionId, options) => {
5674
+ const processResolvedSession = (0, import_react12.useCallback)(async (apiResult, resolvedSessionId, options) => {
4833
5675
  const session = apiResult.data.session ?? null;
4834
5676
  if (!session) {
4835
- throw new import_shared10.FloPayError("No session data returned", "api_error");
5677
+ throw new import_shared11.FloPayError("No session data returned", "api_error");
4836
5678
  }
4837
5679
  if (session.status === "complete") {
4838
5680
  await showSuccess({
@@ -4844,7 +5686,7 @@ function FloPayAutomaticPaymentButton({
4844
5686
  return;
4845
5687
  }
4846
5688
  if (session.status === "expired") {
4847
- throw new import_shared10.FloPayError("Checkout session has expired.", "api_error", {
5689
+ throw new import_shared11.FloPayError("Checkout session has expired.", "api_error", {
4848
5690
  code: "checkout_session_expired"
4849
5691
  });
4850
5692
  }
@@ -4854,13 +5696,13 @@ function FloPayAutomaticPaymentButton({
4854
5696
  const shouldTreatCreateSessionFlowAsServerAutoAttempt = options?.fromCreateSession && (apiResult.autoProcessingAttempted === true || !!apiResult.autoProcessingError || !!redirectResult);
4855
5697
  const shouldRetryPayPalClientSide = checkoutMethod === "paypal" && automaticPaymentToken?.isPaypal === true && options?.fromCreateSession === true;
4856
5698
  if (apiResult.autoProcessingPending) {
4857
- const api = new import_js6.PaymentAPI(resolvedBillingUrl);
5699
+ const api = new import_js7.PaymentAPI(resolvedBillingUrl);
4858
5700
  const completed = await api.waitForCheckoutSessionCompletion(apiResult.autoProcessingPending.sessionId, {
4859
5701
  initialDelayMs: apiResult.autoProcessingPending.retryAfterMs
4860
5702
  });
4861
5703
  const completedSession = completed.data.session;
4862
5704
  if (!completedSession || completedSession.status !== "complete") {
4863
- throw new import_shared10.FloPayError("Automatic payment failed. Please try again.", "api_error", {
5705
+ throw new import_shared11.FloPayError("Automatic payment failed. Please try again.", "api_error", {
4864
5706
  code: completedSession?.status === "expired" ? "checkout_session_expired" : "checkout_processing_timeout"
4865
5707
  });
4866
5708
  }
@@ -4881,7 +5723,7 @@ function FloPayAutomaticPaymentButton({
4881
5723
  publishableKey,
4882
5724
  paypalPublishableKey
4883
5725
  } = resolveSavedPaymentPublishableKeys(apiResult);
4884
- if (redirectResult.type === "paypal_redirect_required") {
5726
+ if (redirectResult.type === "paypal_redirect_required" && publishableKey) {
4885
5727
  persistPayPalResumeState2({
4886
5728
  sessionId: session.id || resolvedSessionId,
4887
5729
  publishableKey,
@@ -4937,7 +5779,7 @@ function FloPayAutomaticPaymentButton({
4937
5779
  publishableKey,
4938
5780
  paypalPublishableKey
4939
5781
  } = resolveSavedPaymentPublishableKeys(apiResult);
4940
- if (result.type === "paypal_redirect_required") {
5782
+ if (result.type === "paypal_redirect_required" && publishableKey) {
4941
5783
  persistPayPalResumeState2({
4942
5784
  sessionId: session.id || resolvedSessionId,
4943
5785
  publishableKey,
@@ -4998,6 +5840,13 @@ function FloPayAutomaticPaymentButton({
4998
5840
  billingApiUrl: resolvedBillingUrl,
4999
5841
  locale
5000
5842
  });
5843
+ if (!flopay) {
5844
+ throw new import_shared11.FloPayError(
5845
+ "Stripe is not available for 3DS authentication.",
5846
+ "api_error",
5847
+ { code: "authentication_required" }
5848
+ );
5849
+ }
5001
5850
  const paymentResult = await processSavedPaymentWithIntent({
5002
5851
  billingApiUrl: resolvedBillingUrl,
5003
5852
  sessionId: fallbackSessionId,
@@ -5052,14 +5901,14 @@ function FloPayAutomaticPaymentButton({
5052
5901
  showError,
5053
5902
  showSuccess
5054
5903
  ]);
5055
- const handleButtonClick = (0, import_react11.useCallback)(async (event) => {
5904
+ const handleButtonClick = (0, import_react12.useCallback)(async (event) => {
5056
5905
  buttonProps.onClick?.(event);
5057
5906
  if (event.defaultPrevented || disabled || isProcessing) {
5058
5907
  return;
5059
5908
  }
5060
5909
  setFallbackSession(null);
5061
5910
  if (sessionId && createSessionDraft) {
5062
- const error = new import_shared10.FloPayError(
5911
+ const error = new import_shared11.FloPayError(
5063
5912
  "Provide either sessionId or create-session props, not both.",
5064
5913
  "validation_error"
5065
5914
  );
@@ -5071,7 +5920,7 @@ function FloPayAutomaticPaymentButton({
5071
5920
  return;
5072
5921
  }
5073
5922
  if (!sessionId && !createSessionDraft) {
5074
- const error = new import_shared10.FloPayError(
5923
+ const error = new import_shared11.FloPayError(
5075
5924
  "Provide a sessionId or the props required to create an automatic payment session.",
5076
5925
  "validation_error"
5077
5926
  );
@@ -5086,7 +5935,7 @@ function FloPayAutomaticPaymentButton({
5086
5935
  setOverlayError(null);
5087
5936
  setOverlayStatus("processing");
5088
5937
  try {
5089
- const api = new import_js6.PaymentAPI(resolvedBillingUrl);
5938
+ const api = new import_js7.PaymentAPI(resolvedBillingUrl);
5090
5939
  if (sessionId) {
5091
5940
  const result = await api.getUnifiedCheckoutSession(sessionId);
5092
5941
  await processResolvedSession(result, sessionId);
@@ -5101,7 +5950,7 @@ function FloPayAutomaticPaymentButton({
5101
5950
  fromCreateSession: true
5102
5951
  });
5103
5952
  } catch (err) {
5104
- if (err instanceof import_shared10.FloPayError && err.code === "session_auto_completed") {
5953
+ if (err instanceof import_shared11.FloPayError && err.code === "session_auto_completed") {
5105
5954
  await showSuccess({
5106
5955
  result: { status: "succeeded" },
5107
5956
  session: null,
@@ -5134,7 +5983,7 @@ function FloPayAutomaticPaymentButton({
5134
5983
  showError,
5135
5984
  showSuccess
5136
5985
  ]);
5137
- const handleFallbackComplete = (0, import_react11.useCallback)((result) => {
5986
+ const handleFallbackComplete = (0, import_react12.useCallback)((result) => {
5138
5987
  const activeFallback = fallbackSessionRef.current;
5139
5988
  setFallbackSession(null);
5140
5989
  onSuccessRef.current?.({
@@ -5144,13 +5993,13 @@ function FloPayAutomaticPaymentButton({
5144
5993
  autoCompleted: false
5145
5994
  });
5146
5995
  }, []);
5147
- const handleFallbackError = (0, import_react11.useCallback)((error) => {
5996
+ const handleFallbackError = (0, import_react12.useCallback)((error) => {
5148
5997
  onErrorRef.current?.(error);
5149
5998
  }, []);
5150
- const handleFallbackDecline = (0, import_react11.useCallback)((decline) => {
5999
+ const handleFallbackDecline = (0, import_react12.useCallback)((decline) => {
5151
6000
  onDeclineRef.current?.(decline);
5152
6001
  }, []);
5153
- (0, import_react11.useEffect)(() => {
6002
+ (0, import_react12.useEffect)(() => {
5154
6003
  if (typeof window === "undefined" || resumeAttemptedRef.current) {
5155
6004
  return;
5156
6005
  }
@@ -5171,7 +6020,7 @@ function FloPayAutomaticPaymentButton({
5171
6020
  try {
5172
6021
  if (params.get("redirect_status") === "failed") {
5173
6022
  throw Object.assign(
5174
- new import_shared10.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
6023
+ new import_shared11.FloPayError("PayPal payment was declined. Please try again.", "api_error"),
5175
6024
  { checkoutMethod: "paypal" }
5176
6025
  );
5177
6026
  }
@@ -5184,17 +6033,17 @@ function FloPayAutomaticPaymentButton({
5184
6033
  billingApiUrl: resolvedBillingUrl,
5185
6034
  locale
5186
6035
  });
5187
- const paypalStripe = (paypalFlopay ?? flopay).getRawProvider();
6036
+ const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
5188
6037
  if (!paypalStripe) {
5189
6038
  throw Object.assign(
5190
- new import_shared10.FloPayError("PayPal is not available.", "api_error"),
6039
+ new import_shared11.FloPayError("PayPal is not available.", "api_error"),
5191
6040
  { checkoutMethod: "paypal" }
5192
6041
  );
5193
6042
  }
5194
6043
  const { paymentIntent, error } = await paypalStripe.retrievePaymentIntent(clientSecret);
5195
6044
  if (error) {
5196
6045
  throw Object.assign(
5197
- new import_shared10.FloPayError(
6046
+ new import_shared11.FloPayError(
5198
6047
  error.message ?? "Failed to retrieve PayPal payment status.",
5199
6048
  "api_error",
5200
6049
  { code: error.code }
@@ -5205,23 +6054,23 @@ function FloPayAutomaticPaymentButton({
5205
6054
  const resultStatus = mapPayPalIntentStatusToPaymentResult(paymentIntent?.status);
5206
6055
  if (!paymentIntent || resultStatus === "failed") {
5207
6056
  throw Object.assign(
5208
- new import_shared10.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
6057
+ new import_shared11.FloPayError("PayPal payment was not completed. Please try again.", "api_error"),
5209
6058
  { checkoutMethod: "paypal" }
5210
6059
  );
5211
6060
  }
5212
6061
  const paymentMethodId2 = typeof paymentIntent.payment_method === "string" ? paymentIntent.payment_method : paymentIntent.payment_method?.id;
5213
6062
  if (!resumeState.sessionId) {
5214
6063
  throw Object.assign(
5215
- new import_shared10.FloPayError("Missing session id on PayPal resume.", "api_error"),
6064
+ new import_shared11.FloPayError("Missing session id on PayPal resume.", "api_error"),
5216
6065
  { checkoutMethod: "paypal" }
5217
6066
  );
5218
6067
  }
5219
- const api = new import_js6.PaymentAPI(resolvedBillingUrl);
6068
+ const api = new import_js7.PaymentAPI(resolvedBillingUrl);
5220
6069
  const sessionResult = await api.getUnifiedCheckoutSession(resumeState.sessionId);
5221
6070
  let resumeSession = sessionResult.data.session;
5222
6071
  if (!resumeSession) {
5223
6072
  throw Object.assign(
5224
- new import_shared10.FloPayError("Could not load session to capture PayPal payment.", "api_error"),
6073
+ new import_shared11.FloPayError("Could not load session to capture PayPal payment.", "api_error"),
5225
6074
  { checkoutMethod: "paypal" }
5226
6075
  );
5227
6076
  }
@@ -5240,7 +6089,7 @@ function FloPayAutomaticPaymentButton({
5240
6089
  });
5241
6090
  if (processResult.type !== "success") {
5242
6091
  throw Object.assign(
5243
- new import_shared10.FloPayError("Failed to finalize PayPal payment.", "api_error"),
6092
+ new import_shared11.FloPayError("Failed to finalize PayPal payment.", "api_error"),
5244
6093
  { checkoutMethod: "paypal" }
5245
6094
  );
5246
6095
  }
@@ -5281,8 +6130,8 @@ function FloPayAutomaticPaymentButton({
5281
6130
  }
5282
6131
  })();
5283
6132
  }, [locale, resolvedBillingUrl, showError, showSuccess]);
5284
- const bStyles = (0, import_react11.useMemo)(() => {
5285
- const base = (0, import_shared10.resolveButtonsLayoutTheme)(buttonsTheme);
6133
+ const bStyles = (0, import_react12.useMemo)(() => {
6134
+ const base = (0, import_shared11.resolveButtonsLayoutTheme)(buttonsTheme);
5286
6135
  if (!stylesOverride) return base;
5287
6136
  return {
5288
6137
  ...base,
@@ -5291,8 +6140,8 @@ function FloPayAutomaticPaymentButton({
5291
6140
  };
5292
6141
  }, [buttonsTheme, stylesOverride]);
5293
6142
  const cardButtonSizing = children === void 0 ? { boxSizing: "border-box", height: DEFAULT_BUTTONS_LAYOUT_BUTTON_HEIGHT3, padding: "0 1rem" } : { padding: "0.9rem 1rem" };
5294
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
5295
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6143
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
6144
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5296
6145
  "button",
5297
6146
  {
5298
6147
  ...buttonProps,
@@ -5333,17 +6182,17 @@ function FloPayAutomaticPaymentButton({
5333
6182
  e.currentTarget.style.transform = "scale(1)";
5334
6183
  }
5335
6184
  },
5336
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CardButtonContentSlot, { content: children })
6185
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CardButtonContentSlot, { content: children })
5337
6186
  }
5338
6187
  ),
5339
- overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6188
+ overlayStatus && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5340
6189
  ProcessingOverlay,
5341
6190
  {
5342
6191
  status: overlayStatus,
5343
6192
  errorMessage: overlayError
5344
6193
  }
5345
6194
  ),
5346
- fallbackSession && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6195
+ fallbackSession && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5347
6196
  "div",
5348
6197
  {
5349
6198
  "data-testid": "flopay-automatic-payment-fallback",
@@ -5364,7 +6213,7 @@ function FloPayAutomaticPaymentButton({
5364
6213
  padding: "1.5rem",
5365
6214
  zIndex: 1100
5366
6215
  },
5367
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6216
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5368
6217
  "div",
5369
6218
  {
5370
6219
  style: {
@@ -5380,7 +6229,7 @@ function FloPayAutomaticPaymentButton({
5380
6229
  flexDirection: "column",
5381
6230
  gap: "1rem"
5382
6231
  },
5383
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
6232
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5384
6233
  FloPayCheckout,
5385
6234
  {
5386
6235
  sessionId: fallbackSession.sessionId,
@@ -5408,6 +6257,7 @@ function FloPayAutomaticPaymentButton({
5408
6257
  CardExpiryElement,
5409
6258
  CardNumberElement,
5410
6259
  CheckoutForm,
6260
+ DirectPayPalButton,
5411
6261
  FloPayAutomaticPaymentButton,
5412
6262
  FloPayCheckout,
5413
6263
  FloPayProvider,