@funnelsgrove/payments 0.1.50 → 0.1.52

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/README.md CHANGED
@@ -24,8 +24,8 @@ Use these for new subscription paywalls:
24
24
 
25
25
  Use these for new one-time paywall plans:
26
26
 
27
- - `createStripePaymentIntent`
28
- - `SharedStripeCheckoutV2Dialog` with `checkoutMode="payment_intent"`
27
+ - `createStripeOneTimeCheckout`
28
+ - `SharedStripeCheckoutV2Dialog`
29
29
 
30
30
  Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the shared client helper fits the funnel. It delegates to `funnelSdkService.chargeOneClickPayment`.
31
31
 
@@ -33,6 +33,7 @@ Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the s
33
33
 
34
34
  Keep these exports available for saved drafts, old published artifacts, and controlled migrations. Do not use them for new subscription checkout work:
35
35
 
36
+ - `createStripePaymentIntent`
36
37
  - `SharedStripeCheckoutDialog`
37
38
  - `ApplePaySubscribeButton`
38
39
  - `GooglePaySubscribeButton`
@@ -68,7 +69,7 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
68
69
  - `services/planCatalog.service`: plan resolution and selection helpers.
69
70
  - `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
70
71
  - `services/paywallOffer.service`: timed discount and display-plan helpers.
71
- - `services/stripe.service`: Stripe loader, checkout-session, hosted checkout, one-click, and one-time PaymentIntent clients.
72
+ - `services/stripe.service`: Stripe loader, Checkout Session, hosted checkout, one-click, one-time Checkout Session clients, and deprecated PaymentIntent compatibility clients.
72
73
  - `providers/*`: provider-neutral checkout state and Stripe subscription checkout slots.
73
74
  - `components/shared/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet placeholders, and trust assets.
74
75
  - `testing/walletCheckoutSmoke`: wallet checkout smoke assertions.
@@ -5,7 +5,6 @@ export type SharedStripeCheckoutV2DialogProps = {
5
5
  buttonColor: string;
6
6
  cardSubmitLabel: string;
7
7
  checkoutAnalytics?: StripeSubscriptionCheckoutAnalyticsContext | null;
8
- checkoutMode?: 'checkout_session' | 'payment_intent';
9
8
  checkoutSessionId?: string | null;
10
9
  clientSecret: string;
11
10
  closeAriaLabel: string;
@@ -64,5 +63,5 @@ export type SharedCheckoutSpecialOfferDialogProps = {
64
63
  themeColor: string;
65
64
  title: string;
66
65
  };
67
- export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutMode, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
66
+ export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
68
67
  export declare function SharedCheckoutSpecialOfferDialog({ buttonColor, buttonLabel, description, discountLabel, imageAlt, imageSrc, onAccept, themeColor, title, }: SharedCheckoutSpecialOfferDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -12,10 +12,8 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
14
  import { useEffect, useMemo, useState, } from 'react';
15
- import { Elements, PaymentElement as PaymentIntentPaymentElement, useElements, useStripe, } from '@stripe/react-stripe-js';
16
15
  import { CheckoutProvider, PaymentElement, useCheckout, } from '@stripe/react-stripe-js/checkout';
17
16
  import { PaymentBrandMark, SecurityLockIcon } from './CheckoutBrandAssets.js';
18
- import { StripeExpressCheckoutButton } from './StripeExpressCheckoutButton.js';
19
17
  import { StripeCheckoutExpressCheckoutButton } from './StripeCheckoutExpressCheckoutButton.js';
20
18
  import { getUnsupportedCheckoutCountryMessage, normalizeSupportedCheckoutCountries, } from './checkoutCountries.js';
21
19
  import { isInactiveCheckoutSessionError } from '../../providers/stripe/useStripeSubscriptionCheckoutSession.js';
@@ -61,23 +59,6 @@ function getFriendlyCardErrorMessage(error) {
61
59
  ? error.message
62
60
  : 'Payment failed. Please review your card details and try again.';
63
61
  }
64
- const normalizeBillingName = (input) => {
65
- var _a, _b, _c;
66
- const normalizedName = (_a = input.name) === null || _a === void 0 ? void 0 : _a.trim();
67
- if (normalizedName) {
68
- return normalizedName;
69
- }
70
- const normalizedEmail = (_b = input.email) === null || _b === void 0 ? void 0 : _b.trim();
71
- if (normalizedEmail) {
72
- const localPart = (_c = normalizedEmail
73
- .split('@')[0]) === null || _c === void 0 ? void 0 : _c.replace(/[._-]+/g, ' ').trim();
74
- if (localPart) {
75
- return localPart;
76
- }
77
- }
78
- return 'Customer';
79
- };
80
- const isSuccessfulIntentStatus = (status) => status === 'succeeded' || status === 'processing' || status === 'requires_capture';
81
62
  function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, checkoutAnalytics, checkoutSessionId, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onInactiveCheckoutSession, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, supportedCountries, themeColor, title, totalLabel, totalValue, unsupportedCountryMessage, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
82
63
  const checkoutState = useCheckout();
83
64
  const walletPaymentMethods = usePlatformWalletPaymentMethods();
@@ -325,270 +306,6 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
325
306
  onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
326
307
  } }) })] }), _jsx(PaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
327
308
  }
328
- function SharedStripeCheckoutV2PaymentIntentForm({ amountCents, buttonColor, cardSubmitLabel, closeAriaLabel, countdownLabel, customerEmail, customerEmailEditable = false, customerEmailLabel = 'Email', customerEmailPlaceholder = 'Enter your email', customerEmailInvalidMessage = 'Enter a valid email address.', customerName, discountAmountLabel, discountLabel, discountPercent, initialWalletAvailable, onClose, onCustomerEmailChange, onCustomerEmailCommit, onError, onPaymentInfoSubmitted, onSuccess, paymentMethodLabels = defaultPaymentMethodLabels, promoActive, processingLabel, promoCode, promoCodeLabel, remainingSeconds, returnUrl, savedLabel, secureLabel, satisfactionLabel, satisfactionPercent, summaryLabel, supportedCountries, themeColor, title, totalLabel, totalValue, unsupportedCountryMessage, walletButtonLabel, originalPriceLabel, originalPriceValue, }) {
329
- const stripe = useStripe();
330
- const elements = useElements();
331
- const walletPaymentMethods = usePlatformWalletPaymentMethods();
332
- const [selectedMethod, setSelectedMethod] = useState('wallet');
333
- const [walletAvailable, setWalletAvailable] = useState(initialWalletAvailable !== null && initialWalletAvailable !== void 0 ? initialWalletAvailable : null);
334
- const effectiveWalletAvailable = initialWalletAvailable === true && walletAvailable !== false
335
- ? true
336
- : walletAvailable;
337
- const [submitting, setSubmitting] = useState(false);
338
- const [error, setError] = useState(null);
339
- const [billingCountry, setBillingCountry] = useState(null);
340
- const initialCustomerEmail = (customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) || '';
341
- const [emailDraft, setEmailDraft] = useState(initialCustomerEmail);
342
- const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
343
- const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
344
- const fixedBillingCountryLabel = fixedBillingCountry
345
- ? getCheckoutCountryLabel(fixedBillingCountry)
346
- : null;
347
- const cardBrandLabels = useMemo(() => paymentMethodLabels.length > 0 ? paymentMethodLabels : defaultPaymentMethodLabels, [paymentMethodLabels]);
348
- const normalizedPromoCode = promoCode.trim();
349
- const showPromo = promoActive !== null && promoActive !== void 0 ? promoActive : (discountPercent > 0 && normalizedPromoCode.length > 0);
350
- const countdownValue = formatCountdown(remainingSeconds);
351
- const resolvedCustomerEmail = customerEmailEditable
352
- ? emailDraft.trim() || initialCustomerEmail
353
- : initialCustomerEmail;
354
- const emailFieldClassName = [
355
- 'shared-checkout-v2-email-field',
356
- customerEmailEditable ? '' : 'is-disabled',
357
- ]
358
- .filter(Boolean)
359
- .join(' ');
360
- const checkoutStyle = {
361
- '--shared-checkout-v2-theme-color': themeColor,
362
- '--shared-checkout-v2-button-color': buttonColor,
363
- };
364
- const expressCheckoutSummaryLabel = (summaryLabel === null || summaryLabel === void 0 ? void 0 : summaryLabel.trim()) || discountLabel || title;
365
- const walletAriaLabel = walletPaymentMethods
366
- .map((method) => method === 'applePay' ? walletButtonLabel : 'Google Pay')
367
- .join(' / ');
368
- const showWalletMethod = effectiveWalletAvailable !== false && walletPaymentMethods.length > 0;
369
- const effectiveSelectedMethod = showWalletMethod && selectedMethod === 'wallet' ? 'wallet' : 'card';
370
- const expressCheckoutOptions = useMemo(() => {
371
- return {
372
- buttonHeight: 55,
373
- buttonTheme: {
374
- applePay: 'black',
375
- googlePay: 'black',
376
- },
377
- buttonType: {
378
- applePay: 'buy',
379
- googlePay: 'buy',
380
- },
381
- layout: {
382
- maxColumns: 1,
383
- maxRows: 2,
384
- overflow: 'auto',
385
- },
386
- lineItems: [
387
- {
388
- name: expressCheckoutSummaryLabel,
389
- amount: amountCents,
390
- },
391
- ],
392
- paymentMethodOrder: getStripeWalletPaymentMethodOrder(walletPaymentMethods),
393
- paymentMethods: {
394
- amazonPay: 'never',
395
- applePay: walletPaymentMethods.includes('applePay') ? 'always' : 'never',
396
- googlePay: walletPaymentMethods.includes('googlePay') ? 'always' : 'never',
397
- klarna: 'never',
398
- link: 'never',
399
- paypal: 'never',
400
- },
401
- };
402
- }, [amountCents, expressCheckoutSummaryLabel, walletPaymentMethods]);
403
- const paymentElementOptions = useMemo(() => {
404
- return Object.assign(Object.assign({ fields: {
405
- billingDetails: {
406
- name: 'never',
407
- email: 'never',
408
- address: {
409
- country: fixedBillingCountry ? 'never' : 'auto',
410
- },
411
- },
412
- } }, (fixedBillingCountry
413
- ? {
414
- defaultValues: {
415
- billingDetails: {
416
- address: {
417
- country: fixedBillingCountry,
418
- },
419
- },
420
- },
421
- }
422
- : {})), { layout: 'tabs', wallets: {
423
- applePay: 'never',
424
- googlePay: 'never',
425
- link: 'never',
426
- } });
427
- }, [fixedBillingCountry]);
428
- const setSharedError = (message) => {
429
- setError(message);
430
- onError === null || onError === void 0 ? void 0 : onError(message);
431
- };
432
- const selectWalletMethod = () => {
433
- if (showWalletMethod) {
434
- setSelectedMethod('wallet');
435
- }
436
- };
437
- const selectCardMethod = () => setSelectedMethod('card');
438
- const handleWalletAvailabilityChange = (available) => {
439
- setWalletAvailable(available);
440
- if (!available && selectedMethod === 'wallet') {
441
- setSelectedMethod('card');
442
- }
443
- };
444
- const getBillingCountryError = (country) => getUnsupportedCheckoutCountryMessage({
445
- billingCountry: country,
446
- message: unsupportedCountryMessage,
447
- supportedCountries: normalizedSupportedCountries,
448
- });
449
- const handlePaymentElementChange = (event) => {
450
- var _a, _b;
451
- setBillingCountry((_b = (_a = event.value.billingDetails) === null || _a === void 0 ? void 0 : _a.address.country) !== null && _b !== void 0 ? _b : fixedBillingCountry);
452
- };
453
- const trackCheckoutSuccess = async () => {
454
- await (onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess());
455
- };
456
- useEffect(() => {
457
- if (effectiveSelectedMethod !== 'card' || typeof window === 'undefined') {
458
- return;
459
- }
460
- const resizeTimer = window.setTimeout(() => {
461
- window.dispatchEvent(new Event('resize'));
462
- }, 0);
463
- return () => window.clearTimeout(resizeTimer);
464
- }, [effectiveSelectedMethod]);
465
- const commitCustomerEmail = async (normalizedEmail) => {
466
- if (!customerEmailEditable || !onCustomerEmailCommit) {
467
- return normalizedEmail;
468
- }
469
- const committedEmail = await onCustomerEmailCommit(normalizedEmail);
470
- const nextEmail = typeof committedEmail === 'string' && committedEmail.trim()
471
- ? committedEmail.trim()
472
- : normalizedEmail;
473
- setEmailDraft(nextEmail);
474
- onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(nextEmail);
475
- return nextEmail;
476
- };
477
- const commitEmailDraftIfValid = (value) => {
478
- const normalizedEmail = value.trim();
479
- if (!customerEmailEditable || !onCustomerEmailCommit) {
480
- return;
481
- }
482
- if (!normalizedEmail || !isValidEmail(normalizedEmail)) {
483
- return;
484
- }
485
- void commitCustomerEmail(normalizedEmail).catch((commitError) => {
486
- setSharedError(getFriendlyCardErrorMessage(commitError));
487
- });
488
- };
489
- const ensureCustomerEmail = async () => {
490
- const normalizedEmail = resolvedCustomerEmail.trim();
491
- if (!normalizedEmail || !isValidEmail(normalizedEmail)) {
492
- setSharedError(customerEmailInvalidMessage);
493
- return null;
494
- }
495
- return commitCustomerEmail(normalizedEmail);
496
- };
497
- const handleSubmit = async (event) => {
498
- var _a;
499
- event.preventDefault();
500
- if (!stripe || !elements || submitting) {
501
- return;
502
- }
503
- const billingCountryError = getBillingCountryError(billingCountry !== null && billingCountry !== void 0 ? billingCountry : fixedBillingCountry);
504
- if (billingCountryError) {
505
- setSharedError(billingCountryError);
506
- return;
507
- }
508
- setSubmitting(true);
509
- setSharedError(null);
510
- try {
511
- const syncedEmail = await ensureCustomerEmail();
512
- if (!syncedEmail) {
513
- setSubmitting(false);
514
- return;
515
- }
516
- const submitResult = await elements.submit();
517
- if (submitResult.error) {
518
- setSharedError(submitResult.error.message || 'Payment form is not ready yet.');
519
- setSubmitting(false);
520
- return;
521
- }
522
- await (onPaymentInfoSubmitted === null || onPaymentInfoSubmitted === void 0 ? void 0 : onPaymentInfoSubmitted());
523
- const result = await stripe.confirmPayment({
524
- elements,
525
- confirmParams: {
526
- payment_method_data: {
527
- billing_details: {
528
- email: syncedEmail || undefined,
529
- name: normalizeBillingName({
530
- email: syncedEmail,
531
- name: customerName,
532
- }),
533
- },
534
- },
535
- return_url: returnUrl,
536
- },
537
- redirect: 'if_required',
538
- });
539
- if (result.error) {
540
- const message = result.error.message || 'Payment failed.';
541
- setSharedError(message);
542
- setSubmitting(false);
543
- return;
544
- }
545
- if (typeof window !== 'undefined' &&
546
- isSuccessfulIntentStatus((_a = result.paymentIntent) === null || _a === void 0 ? void 0 : _a.status)) {
547
- await trackCheckoutSuccess();
548
- window.location.assign(returnUrl);
549
- return;
550
- }
551
- setSubmitting(false);
552
- }
553
- catch (submitError) {
554
- setSharedError(getFriendlyCardErrorMessage(submitError));
555
- setSubmitting(false);
556
- }
557
- };
558
- const visibleError = error;
559
- return (_jsxs("div", { className: 'shared-checkout-v2-shell', style: checkoutStyle, children: [_jsxs("header", { className: 'shared-checkout-v2-header', children: [_jsx("button", { type: 'button', className: 'shared-checkout-v2-close', onClick: onClose, "aria-label": closeAriaLabel, children: _jsx("span", { "aria-hidden": 'true' }) }), _jsx("h2", { id: 'shared-checkout-v2-title', children: title })] }), _jsxs("section", { className: 'shared-checkout-v2-summary', children: [showPromo ? (_jsxs("p", { className: 'shared-checkout-v2-countdown', children: [discountPercent, "% ", countdownLabel, " ", countdownValue, " min"] })) : null, _jsxs("p", { className: 'shared-checkout-v2-satisfaction', children: [_jsx("strong", { children: satisfactionPercent }), " ", satisfactionLabel] }), showPromo ? (_jsxs("div", { className: 'shared-checkout-v2-price-stack', children: [_jsxs("div", { className: 'shared-checkout-v2-price-row is-muted', children: [_jsx("span", { children: originalPriceLabel }), _jsx("span", { className: 'shared-checkout-v2-strike', children: originalPriceValue })] }), _jsxs("div", { className: 'shared-checkout-v2-price-row is-discount', children: [_jsx("strong", { children: discountLabel }), _jsx("strong", { children: discountAmountLabel })] }), _jsxs("div", { className: 'shared-checkout-v2-promo', children: [_jsx("span", { children: promoCodeLabel }), _jsx("strong", { children: normalizedPromoCode })] })] })) : null, _jsxs("div", { className: [
560
- 'shared-checkout-v2-total',
561
- showPromo ? '' : 'is-plain',
562
- ]
563
- .filter(Boolean)
564
- .join(' '), children: [_jsx("span", { children: totalLabel }), _jsxs("strong", { children: [_jsx("svg", { viewBox: '0 0 24 24', "aria-hidden": 'true', children: _jsx("path", { d: 'M20.6 13.4 12.4 21.6a2.2 2.2 0 0 1-3.1 0L2.4 14.7a2.2 2.2 0 0 1-.6-1.6V5.4a2 2 0 0 1 2-2h7.7a2.2 2.2 0 0 1 1.6.6l7.5 7.5a1.4 1.4 0 0 1 0 1.9ZM7.2 8.1a1.2 1.2 0 1 0 0-2.4 1.2 1.2 0 0 0 0 2.4Z' }) }), totalValue] })] }), showPromo ? (_jsxs("p", { className: 'shared-checkout-v2-saved', children: [_jsx("span", { "aria-hidden": 'true', children: "\uD83D\uDD25" }), savedLabel] })) : null] }), _jsxs("form", { className: 'shared-checkout-v2-payment', onSubmit: (event) => void handleSubmit(event), children: [showWalletMethod ? (_jsxs("div", { className: 'shared-checkout-v2-methods', role: 'tablist', "aria-label": 'Payment method', children: [_jsxs("button", { type: 'button', className: [
565
- 'shared-checkout-v2-method',
566
- effectiveSelectedMethod === 'wallet' ? 'is-selected' : '',
567
- ]
568
- .filter(Boolean)
569
- .join(' '), onClick: selectWalletMethod, role: 'tab', "aria-selected": effectiveSelectedMethod === 'wallet', children: [_jsxs("span", { className: 'shared-checkout-v2-tab-wallets', "aria-hidden": 'true', children: [walletPaymentMethods.includes('applePay') ? (_jsx(PaymentBrandMark, { label: 'Apple Pay', className: 'shared-checkout-v2-tab-wallet' })) : null, walletPaymentMethods.includes('googlePay') ? (_jsx(PaymentBrandMark, { label: 'Google Pay', className: 'shared-checkout-v2-tab-wallet' })) : null] }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] }), _jsxs("button", { type: 'button', className: [
570
- 'shared-checkout-v2-method',
571
- effectiveSelectedMethod === 'card' ? 'is-selected' : '',
572
- ]
573
- .filter(Boolean)
574
- .join(' '), onClick: selectCardMethod, role: 'tab', "aria-selected": effectiveSelectedMethod === 'card', children: [_jsx("strong", { children: "Credit card" }), _jsx("span", { className: 'shared-checkout-v2-tab-brands', "aria-hidden": 'true', children: cardBrandLabels.slice(0, 4).map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-tab-brand' }, label))) })] })] })) : null, _jsxs("div", { hidden: effectiveSelectedMethod !== 'wallet', className: [
575
- 'shared-checkout-v2-wallet-panel',
576
- effectiveSelectedMethod === 'wallet' ? 'is-visible' : '',
577
- ]
578
- .filter(Boolean)
579
- .join(' '), children: [_jsxs("p", { className: 'shared-checkout-v2-secure-pill', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] }), _jsxs("div", { className: 'shared-checkout-v2-wallet-shell', "aria-label": walletAriaLabel, children: [_jsx(StripeExpressCheckoutButton, { amountCents: amountCents, availabilityPaymentMethods: walletPaymentMethods, beforeConfirm: ensureCustomerEmail, className: 'shared-checkout-v2-express-buttons', customerEmail: resolvedCustomerEmail, customerName: customerName, initialAvailable: initialWalletAvailable, keepInitialAvailableOnReady: initialWalletAvailable === true, onAvailabilityChange: handleWalletAvailabilityChange, onError: setSharedError, onPaymentInfoSubmitted: onPaymentInfoSubmitted, onSuccess: trackCheckoutSuccess, options: expressCheckoutOptions, returnUrl: returnUrl, summaryLabel: expressCheckoutSummaryLabel }), _jsx("span", { className: 'shared-checkout-v2-sr-only', children: walletAriaLabel })] })] }), _jsxs("div", { hidden: effectiveSelectedMethod !== 'card', className: [
580
- 'shared-checkout-v2-card-panel',
581
- effectiveSelectedMethod === 'card' ? 'is-visible' : '',
582
- ]
583
- .filter(Boolean)
584
- .join(' '), children: [_jsxs("div", { className: 'shared-checkout-v2-card-box', children: [_jsxs("label", { className: emailFieldClassName, children: [_jsx("span", { className: 'shared-checkout-v2-email-label', children: customerEmailLabel }), _jsx("span", { className: 'shared-checkout-v2-email-control', children: _jsx("input", { type: 'email', autoComplete: 'email', className: 'shared-checkout-v2-email-input', disabled: !customerEmailEditable, inputMode: 'email', readOnly: !customerEmailEditable, value: customerEmailEditable ? emailDraft : initialCustomerEmail, placeholder: customerEmailPlaceholder, onBlur: (event) => commitEmailDraftIfValid(event.currentTarget.value), onChange: (event) => {
585
- if (!customerEmailEditable) {
586
- return;
587
- }
588
- setEmailDraft(event.target.value);
589
- onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
590
- } }) })] }), _jsx(PaymentIntentPaymentElement, { options: paymentElementOptions, onChange: handlePaymentElementChange }), fixedBillingCountry && fixedBillingCountryLabel ? (_jsxs("label", { className: 'shared-checkout-v2-country-field', children: [_jsx("span", { className: 'shared-checkout-v2-country-label', children: "Country" }), _jsx("span", { className: 'shared-checkout-v2-country-control', children: _jsx("select", { "aria-label": 'Country', className: 'shared-checkout-v2-country-select', value: fixedBillingCountry, onChange: () => setBillingCountry(fixedBillingCountry), children: _jsx("option", { value: fixedBillingCountry, children: fixedBillingCountryLabel }) }) })] })) : null] }), visibleError ? _jsx("p", { className: 'shared-checkout-v2-error', children: visibleError }) : null, _jsxs("button", { type: 'submit', className: 'shared-checkout-v2-card-submit', disabled: submitting, children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-card-submit-icon' }), submitting ? processingLabel : cardSubmitLabel] }), _jsx("div", { className: 'shared-checkout-v2-card-brands', "aria-hidden": 'true', children: cardBrandLabels.map((label) => (_jsx(PaymentBrandMark, { label: label, className: 'shared-checkout-v2-card-brand' }, label))) }), _jsxs("p", { className: 'shared-checkout-v2-secure-pill shared-checkout-v2-secure-pill--card', children: [_jsx(SecurityLockIcon, { className: 'shared-checkout-v2-secure-pill-icon' }), secureLabel] })] })] })] }));
591
- }
592
309
  function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry, stripePromise, }) {
593
310
  const providerChildren = children;
594
311
  const checkoutProviderOptions = useMemo(() => (Object.assign(Object.assign({ clientSecret }, (fixedBillingCountry
@@ -606,24 +323,16 @@ function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry,
606
323
  } })), [clientSecret, fixedBillingCountry]);
607
324
  return (_jsx(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: providerChildren }, clientSecret));
608
325
  }
609
- function PaymentIntentProvider({ children, clientSecret, stripePromise, }) {
610
- const providerChildren = children;
611
- const elementsOptions = useMemo(() => ({
612
- clientSecret,
613
- appearance: stripeCheckoutV2Appearance,
614
- }), [clientSecret]);
615
- return (_jsx(Elements, { stripe: stripePromise, options: elementsOptions, children: providerChildren }, clientSecret));
616
- }
617
326
  export function SharedStripeCheckoutV2Dialog(_a) {
618
- var { checkoutAnalytics, checkoutMode = 'checkout_session', checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutMode", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries"]);
327
+ var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries"]);
619
328
  const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
620
329
  const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
621
330
  useEffect(() => {
622
- if (checkoutMode !== 'checkout_session' || !checkoutAnalytics) {
331
+ if (!checkoutAnalytics) {
623
332
  return;
624
333
  }
625
334
  void trackStripeSubscriptionCheckoutStarted(Object.assign({ checkoutSessionId }, checkoutAnalytics));
626
- }, [checkoutAnalytics, checkoutMode, checkoutSessionId, clientSecret]);
335
+ }, [checkoutAnalytics, checkoutSessionId, clientSecret]);
627
336
  useEffect(() => {
628
337
  const handleKeyDown = (event) => {
629
338
  if (event.key === 'Escape') {
@@ -633,7 +342,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
633
342
  window.addEventListener('keydown', handleKeyDown);
634
343
  return () => window.removeEventListener('keydown', handleKeyDown);
635
344
  }, [onClose]);
636
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: checkoutMode === 'payment_intent' ? (_jsx(PaymentIntentProvider, { clientSecret: clientSecret, stripePromise: stripePromise, children: _jsx(SharedStripeCheckoutV2PaymentIntentForm, Object.assign({}, props, { clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) })) : (_jsx(CheckoutSessionProvider, { clientSecret: clientSecret, fixedBillingCountry: fixedBillingCountry, stripePromise: stripePromise, children: _jsx(SharedStripeCheckoutV2CheckoutSessionForm, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) })) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
345
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: _jsx(CheckoutSessionProvider, { clientSecret: clientSecret, fixedBillingCountry: fixedBillingCountry, stripePromise: stripePromise, children: _jsx(SharedStripeCheckoutV2CheckoutSessionForm, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries })) }) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
637
346
  }
638
347
  function SharedCheckoutSpecialOfferGift({ discountLabel, imageAlt, imageSrc, }) {
639
348
  if (imageSrc) {
@@ -15,5 +15,5 @@ import { CheckoutProvider } from '@stripe/react-stripe-js/checkout';
15
15
  import { StripeCheckoutExpressCheckoutButton, } from './StripeCheckoutExpressCheckoutButton.js';
16
16
  export function StripeExpressCheckoutElement(_a) {
17
17
  var { appearance, clientSecret, stripePromise } = _a, buttonProps = __rest(_a, ["appearance", "clientSecret", "stripePromise"]);
18
- return (_jsx(CheckoutProvider, { stripe: stripePromise, options: Object.assign({ clientSecret }, (appearance ? { elementsOptions: { appearance } } : {})), children: _jsx(StripeCheckoutExpressCheckoutButton, Object.assign({}, buttonProps)) }));
18
+ return (_jsx(CheckoutProvider, { stripe: stripePromise, options: Object.assign({ clientSecret }, (appearance ? { elementsOptions: { appearance } } : {})), children: _jsx(StripeCheckoutExpressCheckoutButton, Object.assign({}, buttonProps)) }, clientSecret));
19
19
  }
@@ -60,6 +60,26 @@ type CreatePaymentIntentResponse = {
60
60
  stripePublishableKey?: string;
61
61
  environment?: 'test' | 'live';
62
62
  };
63
+ type CreateOneTimeCheckoutInput = {
64
+ plan: CheckoutSessionPlanInput;
65
+ couponId?: string | null;
66
+ analyticsMetadata?: Record<string, unknown> | null;
67
+ customerEmail?: string | null;
68
+ returnUrl: string;
69
+ user_id?: string | null;
70
+ environment?: RuntimeMode;
71
+ runtimeConfig?: StripeRuntimeConfigOverrides;
72
+ };
73
+ type CreateOneTimeCheckoutResponse = {
74
+ clientSecret: string;
75
+ checkoutSessionId?: string;
76
+ stripePublishableKey?: string;
77
+ environment?: 'test' | 'live';
78
+ };
79
+ export declare function createStripeOneTimeCheckout(input: CreateOneTimeCheckoutInput): Promise<CreateOneTimeCheckoutResponse>;
80
+ /**
81
+ * @deprecated Use createStripeOneTimeCheckout for one-time paywall checkout.
82
+ */
63
83
  export declare function createStripePaymentIntent(input: CreatePaymentIntentInput): Promise<CreatePaymentIntentResponse>;
64
84
  type ChargeOneClickPaymentInput = {
65
85
  planId: string;
@@ -531,6 +531,26 @@ const normalizeCheckoutAnalyticsMetadata = (metadata, plan) => {
531
531
  }
532
532
  return Object.assign(Object.assign({}, (normalized !== null && normalized !== void 0 ? normalized : {})), { analyticsPurchaseValue });
533
533
  };
534
+ export async function createStripeOneTimeCheckout(input) {
535
+ var _a, _b, _c, _d, _e;
536
+ return funnelSdkService.createOneTimeCheckout({
537
+ planId: getPaywallPlanSelectionValue(input.plan),
538
+ providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
539
+ title: input.plan.title,
540
+ description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
541
+ amountCents: input.plan.amountCents,
542
+ couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
543
+ analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
544
+ customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
545
+ returnUrl: input.returnUrl,
546
+ userId: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
547
+ environment: input.environment,
548
+ runtimeConfig: input.runtimeConfig,
549
+ });
550
+ }
551
+ /**
552
+ * @deprecated Use createStripeOneTimeCheckout for one-time paywall checkout.
553
+ */
534
554
  export async function createStripePaymentIntent(input) {
535
555
  var _a, _b;
536
556
  return funnelSdkService.createOneTimePaymentIntent({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@funnelsgrove/analytics": "^0.1.28",
31
- "@funnelsgrove/runtime": "^0.1.46",
31
+ "@funnelsgrove/runtime": "^0.1.54",
32
32
  "@stripe/react-stripe-js": "^5.6.0",
33
33
  "@stripe/stripe-js": "^8.7.0",
34
34
  "react": "19.2.3",