@flopay/react 1.2.6 → 1.2.8
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 +96 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.mjs +99 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
package/dist/index.cjs
CHANGED
|
@@ -633,6 +633,18 @@ function resolvePaymentIntentPaymentMethodId(paymentIntent) {
|
|
|
633
633
|
}
|
|
634
634
|
async function retrievePaymentIntentFromProvider(provider, clientSecret) {
|
|
635
635
|
const retriever = provider;
|
|
636
|
+
if ((0, import_shared3.isSetupIntentClientSecret)(clientSecret)) {
|
|
637
|
+
if (!retriever?.retrieveSetupIntent) {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
const { setupIntent, error: error2 } = await retriever.retrieveSetupIntent(clientSecret);
|
|
641
|
+
if (error2) {
|
|
642
|
+
throw new import_shared3.FloPayError(error2.message ?? "Failed to retrieve setup intent.", "api_error", {
|
|
643
|
+
...error2.code ? { code: error2.code } : {}
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
return setupIntent ?? null;
|
|
647
|
+
}
|
|
636
648
|
if (!retriever?.retrievePaymentIntent) {
|
|
637
649
|
return null;
|
|
638
650
|
}
|
|
@@ -644,6 +656,12 @@ async function retrievePaymentIntentFromProvider(provider, clientSecret) {
|
|
|
644
656
|
}
|
|
645
657
|
return paymentIntent ?? null;
|
|
646
658
|
}
|
|
659
|
+
function resolveWalletElementsMode(amountInMinorUnits) {
|
|
660
|
+
if (typeof amountInMinorUnits !== "number" || !Number.isFinite(amountInMinorUnits) || amountInMinorUnits <= 0) {
|
|
661
|
+
return { mode: "setup" };
|
|
662
|
+
}
|
|
663
|
+
return { mode: "payment", amount: amountInMinorUnits };
|
|
664
|
+
}
|
|
647
665
|
function resolveTokenizedPaymentMethodId(tokenizedBody) {
|
|
648
666
|
const candidates = [
|
|
649
667
|
tokenizedBody?.id,
|
|
@@ -1761,10 +1779,7 @@ function WalletButtonInner({
|
|
|
1761
1779
|
const intentJson = await intentResponse.json();
|
|
1762
1780
|
const intentClientSecret = intentJson.data?.id;
|
|
1763
1781
|
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
1764
|
-
const { error: confirmError,
|
|
1765
|
-
intentClientSecret,
|
|
1766
|
-
{ payment_method: paymentMethod.id }
|
|
1767
|
-
);
|
|
1782
|
+
const { error: confirmError, intentId } = (0, import_shared6.isSetupIntentClientSecret)(intentClientSecret) ? await stripe.confirmCardSetup(intentClientSecret, { payment_method: paymentMethod.id }).then((r) => ({ error: r.error, intentId: r.setupIntent?.id })) : await stripe.confirmCardPayment(intentClientSecret, { payment_method: paymentMethod.id }).then((r) => ({ error: r.error, intentId: r.paymentIntent?.id }));
|
|
1768
1783
|
if (confirmError) {
|
|
1769
1784
|
const message = confirmError.message ?? "Wallet payment failed.";
|
|
1770
1785
|
onErrorChange?.(message);
|
|
@@ -1776,7 +1791,7 @@ function WalletButtonInner({
|
|
|
1776
1791
|
onTokenizedBody({
|
|
1777
1792
|
id: paymentMethod.id,
|
|
1778
1793
|
type: "card",
|
|
1779
|
-
threeDSecureActionResultTokenId:
|
|
1794
|
+
threeDSecureActionResultTokenId: intentId
|
|
1780
1795
|
}, {
|
|
1781
1796
|
accountPatch: prepared?.accountPatch,
|
|
1782
1797
|
sessionId: effectiveSessionId,
|
|
@@ -2639,14 +2654,17 @@ function SplitCardFormInner({
|
|
|
2639
2654
|
}
|
|
2640
2655
|
};
|
|
2641
2656
|
}, [appearance]);
|
|
2642
|
-
const walletOptions = (0, import_react8.useMemo)(() =>
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2657
|
+
const walletOptions = (0, import_react8.useMemo)(() => {
|
|
2658
|
+
const modeOptions = resolveWalletElementsMode(totalAmount);
|
|
2659
|
+
return {
|
|
2660
|
+
...modeOptions,
|
|
2661
|
+
currency: currency.toLowerCase(),
|
|
2662
|
+
paymentMethodCreation: "manual",
|
|
2663
|
+
// captureMethod only applies to payment mode; Stripe rejects it in setup.
|
|
2664
|
+
...modeOptions.mode === "payment" ? { captureMethod: "manual" } : {},
|
|
2665
|
+
...stripeAppearanceProp
|
|
2666
|
+
};
|
|
2667
|
+
}, [totalAmount, currency, stripeAppearanceProp]);
|
|
2650
2668
|
const paypalOptions = (0, import_react8.useMemo)(() => ({
|
|
2651
2669
|
mode: "payment",
|
|
2652
2670
|
amount: amountInCents,
|
|
@@ -4318,6 +4336,26 @@ function SplitCardFormInner({
|
|
|
4318
4336
|
var import_js3 = require("@flopay/js");
|
|
4319
4337
|
var import_shared7 = require("@flopay/shared");
|
|
4320
4338
|
var DEFAULT_SAVED_PAYMENT_DECLINE_METHOD = "card";
|
|
4339
|
+
async function retrieveResumeIntent(stripe, clientSecret, isSetupIntent) {
|
|
4340
|
+
if (isSetupIntent) {
|
|
4341
|
+
if (typeof stripe.retrieveSetupIntent !== "function") return null;
|
|
4342
|
+
const { setupIntent, error: error2 } = await stripe.retrieveSetupIntent(clientSecret);
|
|
4343
|
+
return { error: error2, intent: setupIntent ?? null };
|
|
4344
|
+
}
|
|
4345
|
+
if (typeof stripe.retrievePaymentIntent !== "function") return null;
|
|
4346
|
+
const { paymentIntent, error } = await stripe.retrievePaymentIntent(clientSecret);
|
|
4347
|
+
return { error, intent: paymentIntent ?? null };
|
|
4348
|
+
}
|
|
4349
|
+
async function confirmResumeIntent(stripe, clientSecret, data, isSetupIntent) {
|
|
4350
|
+
if (isSetupIntent) {
|
|
4351
|
+
if (typeof stripe.confirmCardSetup !== "function") return null;
|
|
4352
|
+
const { setupIntent, error: error2 } = await stripe.confirmCardSetup(clientSecret, data);
|
|
4353
|
+
return { error: error2, intent: setupIntent ?? null };
|
|
4354
|
+
}
|
|
4355
|
+
if (typeof stripe.confirmCardPayment !== "function") return null;
|
|
4356
|
+
const { paymentIntent, error } = await stripe.confirmCardPayment(clientSecret, data);
|
|
4357
|
+
return { error, intent: paymentIntent ?? null };
|
|
4358
|
+
}
|
|
4321
4359
|
function getRedirectResultFromCheckoutProcessError(error) {
|
|
4322
4360
|
if (!error?.type || !error.threeDSecureToken) {
|
|
4323
4361
|
return null;
|
|
@@ -4446,11 +4484,13 @@ async function processSavedPaymentForMode({
|
|
|
4446
4484
|
billingApiUrl,
|
|
4447
4485
|
sessionId,
|
|
4448
4486
|
session,
|
|
4487
|
+
nonce,
|
|
4449
4488
|
tokenizedData,
|
|
4450
4489
|
returnUrl
|
|
4451
4490
|
}) {
|
|
4452
4491
|
const baseUrl = billingApiUrl.replace(/\/+$/, "");
|
|
4453
4492
|
const resolvedSessionId = sessionId ?? session.id;
|
|
4493
|
+
const resolvedNonce = nonce ?? session.clientSecret;
|
|
4454
4494
|
const customerId = session.customer?.id ?? session.accountData?.userId ?? "";
|
|
4455
4495
|
const customerEmail = session.customer?.email ?? session.accountData?.email ?? "";
|
|
4456
4496
|
const firstName = session.customer?.firstName ?? session.accountData?.firstName ?? "";
|
|
@@ -4460,7 +4500,7 @@ async function processSavedPaymentForMode({
|
|
|
4460
4500
|
const api = new import_js3.PaymentAPI(baseUrl);
|
|
4461
4501
|
const response = await retryOnceOnFetchFailure(() => api.processPayment(customerId, {
|
|
4462
4502
|
sessionId: resolvedSessionId,
|
|
4463
|
-
nonce:
|
|
4503
|
+
nonce: resolvedNonce,
|
|
4464
4504
|
tokenizedData,
|
|
4465
4505
|
accountData: {
|
|
4466
4506
|
userId: customerId,
|
|
@@ -4503,7 +4543,7 @@ async function processSavedPaymentForMode({
|
|
|
4503
4543
|
const recoveredRedirect = await recover3DSRedirectResult({
|
|
4504
4544
|
billingApiUrl: baseUrl,
|
|
4505
4545
|
sessionId: resolvedSessionId,
|
|
4506
|
-
nonce:
|
|
4546
|
+
nonce: resolvedNonce,
|
|
4507
4547
|
responseJson: json
|
|
4508
4548
|
});
|
|
4509
4549
|
if (recoveredRedirect) {
|
|
@@ -4551,64 +4591,66 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
4551
4591
|
{ checkoutMethod: "card" }
|
|
4552
4592
|
);
|
|
4553
4593
|
}
|
|
4594
|
+
const isSetupIntent = (0, import_shared7.isSetupIntentClientSecret)(redirectResult.threeDSecureToken);
|
|
4554
4595
|
let paymentIntent = null;
|
|
4555
4596
|
let savedPaymentMethodId = redirectResult.paymentMethodId;
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
);
|
|
4560
|
-
if (retrieveError) {
|
|
4597
|
+
const retrieved = await retrieveResumeIntent(stripe, redirectResult.threeDSecureToken, isSetupIntent);
|
|
4598
|
+
if (retrieved) {
|
|
4599
|
+
if (retrieved.error) {
|
|
4561
4600
|
throw Object.assign(
|
|
4562
4601
|
new import_shared7.FloPayError(
|
|
4563
|
-
|
|
4602
|
+
retrieved.error.message ?? `Failed to retrieve 3DS ${isSetupIntent ? "setup" : "payment"} status.`,
|
|
4564
4603
|
"api_error",
|
|
4565
|
-
{ code:
|
|
4604
|
+
{ code: retrieved.error.code }
|
|
4566
4605
|
),
|
|
4567
4606
|
{ checkoutMethod: "card" }
|
|
4568
4607
|
);
|
|
4569
4608
|
}
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4609
|
+
const existingIntent = retrieved.intent;
|
|
4610
|
+
if (!savedPaymentMethodId && existingIntent?.payment_method) {
|
|
4611
|
+
if (typeof existingIntent.payment_method === "string") {
|
|
4612
|
+
savedPaymentMethodId = existingIntent.payment_method;
|
|
4613
|
+
} else if ("id" in existingIntent.payment_method) {
|
|
4614
|
+
savedPaymentMethodId = existingIntent.payment_method.id ?? void 0;
|
|
4575
4615
|
}
|
|
4576
4616
|
}
|
|
4577
4617
|
}
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4618
|
+
const confirmed = savedPaymentMethodId ? await confirmResumeIntent(
|
|
4619
|
+
stripe,
|
|
4620
|
+
redirectResult.threeDSecureToken,
|
|
4621
|
+
{
|
|
4622
|
+
payment_method: savedPaymentMethodId,
|
|
4623
|
+
return_url: returnUrl ?? resolveSavedPaymentReturnUrl(session) ?? window.location.href
|
|
4624
|
+
},
|
|
4625
|
+
isSetupIntent
|
|
4626
|
+
) : null;
|
|
4627
|
+
if (confirmed) {
|
|
4628
|
+
if (confirmed.error) {
|
|
4587
4629
|
throw Object.assign(
|
|
4588
4630
|
new import_shared7.FloPayError(
|
|
4589
|
-
|
|
4631
|
+
confirmed.error.message ?? "3DS authentication failed.",
|
|
4590
4632
|
"api_error",
|
|
4591
|
-
{ code:
|
|
4633
|
+
{ code: confirmed.error.code }
|
|
4592
4634
|
),
|
|
4593
4635
|
{ checkoutMethod: "card" }
|
|
4594
4636
|
);
|
|
4595
4637
|
}
|
|
4596
|
-
paymentIntent =
|
|
4638
|
+
paymentIntent = confirmed.intent;
|
|
4597
4639
|
} else {
|
|
4598
|
-
const
|
|
4640
|
+
const nextAction = await stripe.handleNextAction({
|
|
4599
4641
|
clientSecret: redirectResult.threeDSecureToken
|
|
4600
4642
|
});
|
|
4601
|
-
if (
|
|
4643
|
+
if (nextAction.error) {
|
|
4602
4644
|
throw Object.assign(
|
|
4603
4645
|
new import_shared7.FloPayError(
|
|
4604
|
-
|
|
4646
|
+
nextAction.error.message ?? "3DS authentication failed.",
|
|
4605
4647
|
"api_error",
|
|
4606
|
-
{ code:
|
|
4648
|
+
{ code: nextAction.error.code }
|
|
4607
4649
|
),
|
|
4608
4650
|
{ checkoutMethod: "card" }
|
|
4609
4651
|
);
|
|
4610
4652
|
}
|
|
4611
|
-
paymentIntent =
|
|
4653
|
+
paymentIntent = (isSetupIntent ? nextAction.setupIntent : nextAction.paymentIntent) ?? null;
|
|
4612
4654
|
}
|
|
4613
4655
|
if (paymentIntent && (paymentIntent.status === "requires_capture" || paymentIntent.status === "succeeded" || paymentIntent.status === "processing")) {
|
|
4614
4656
|
const followUp = await processSavedPaymentForMode({
|
|
@@ -6681,6 +6723,7 @@ function resolveCreateSessionDraft(props) {
|
|
|
6681
6723
|
}
|
|
6682
6724
|
function FloPayAutomaticPaymentButton({
|
|
6683
6725
|
sessionId,
|
|
6726
|
+
nonce,
|
|
6684
6727
|
createSession,
|
|
6685
6728
|
// Deprecated — accepted for back-compat and silently ignored. Backend
|
|
6686
6729
|
// resolves the customer's latest payment method server-side.
|
|
@@ -6812,6 +6855,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
6812
6855
|
if (!session) {
|
|
6813
6856
|
throw new import_shared11.FloPayError("No session data returned", "api_error");
|
|
6814
6857
|
}
|
|
6858
|
+
const effectiveNonce = session.clientSecret || nonce;
|
|
6815
6859
|
if (session.status === "complete") {
|
|
6816
6860
|
await showSuccess({
|
|
6817
6861
|
result: { status: "succeeded" },
|
|
@@ -6867,7 +6911,8 @@ function FloPayAutomaticPaymentButton({
|
|
|
6867
6911
|
const result = await processSavedPaymentForMode({
|
|
6868
6912
|
billingApiUrl: resolvedBillingUrl,
|
|
6869
6913
|
sessionId: resolvedSessionId ?? session.id,
|
|
6870
|
-
session
|
|
6914
|
+
session,
|
|
6915
|
+
nonce: effectiveNonce
|
|
6871
6916
|
});
|
|
6872
6917
|
if (result.type !== "success") {
|
|
6873
6918
|
throw checkoutProcessErrorToFloPayError(
|
|
@@ -6894,11 +6939,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
6894
6939
|
if (shouldShowFallbackCheckout(floPayErr, fallbackSessionId) && fallbackSessionId && isMountedRef.current) {
|
|
6895
6940
|
setFallbackSession({
|
|
6896
6941
|
sessionId: fallbackSessionId,
|
|
6897
|
-
errorMessage: floPayErr.message
|
|
6942
|
+
errorMessage: floPayErr.message,
|
|
6943
|
+
nonce: effectiveNonce || void 0
|
|
6898
6944
|
});
|
|
6899
6945
|
}
|
|
6900
6946
|
}
|
|
6901
6947
|
}, [
|
|
6948
|
+
nonce,
|
|
6902
6949
|
resolvedBillingUrl,
|
|
6903
6950
|
showError,
|
|
6904
6951
|
showSuccess
|
|
@@ -6939,7 +6986,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
6939
6986
|
try {
|
|
6940
6987
|
const api = new import_js7.PaymentAPI(resolvedBillingUrl);
|
|
6941
6988
|
if (sessionId) {
|
|
6942
|
-
const result = await api.getUnifiedCheckoutSession(sessionId);
|
|
6989
|
+
const result = await api.getUnifiedCheckoutSession(sessionId, nonce);
|
|
6943
6990
|
await processResolvedSession(result, sessionId);
|
|
6944
6991
|
return;
|
|
6945
6992
|
}
|
|
@@ -6978,6 +7025,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
6978
7025
|
createSessionDraft,
|
|
6979
7026
|
disabled,
|
|
6980
7027
|
isProcessing,
|
|
7028
|
+
nonce,
|
|
6981
7029
|
processResolvedSession,
|
|
6982
7030
|
resolvedBillingUrl,
|
|
6983
7031
|
sessionId,
|
|
@@ -7112,6 +7160,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
7112
7160
|
FloPayCheckout,
|
|
7113
7161
|
{
|
|
7114
7162
|
sessionId: fallbackSession.sessionId,
|
|
7163
|
+
nonce: fallbackSession.nonce,
|
|
7115
7164
|
checkoutMode: "full",
|
|
7116
7165
|
billingApiUrl: resolvedBillingUrl,
|
|
7117
7166
|
locale,
|