@funnelsgrove/payments 0.7.20 → 0.7.22

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
@@ -32,6 +32,10 @@ Use these for new one-time paywall plans:
32
32
  - `createStripeOneTimeCheckout`
33
33
  - `SharedStripeCheckoutV2Dialog`
34
34
 
35
+ `SharedStripeCheckoutV2Dialog` defaults to the existing full-screen `standard` surface. Pass
36
+ `variant='compact'` for a centered desktop modal with the same Stripe-owned wallet/card flow;
37
+ mobile remains full-screen and all checkout analytics and verified-success behavior are unchanged.
38
+
35
39
  Use `completeStripeOneClickPayment` for normal post-checkout one-click upsells. It delegates the charge to `funnelSdkService.chargeOneClickPayment` and owns any required Stripe confirmation. `chargeStripeOneClickPayment` remains the lower-level charge-only primitive.
36
40
 
37
41
  Solidgate browser checkout is available for controlled provider-routed funnels through
@@ -94,7 +98,7 @@ When a live funnel still uses one of these, migrate the funnel deliberately with
94
98
  - `providers/solidgate/components/*`: the official-SDK checkout dialog and canonical verification lifecycle.
95
99
  - `components/ManageSubscriptionScreen`: provider-neutral subscription management UI.
96
100
 
97
- Funnels should call `resolvePublishedBillingRuntime` once at their runtime-provider boundary. Screens consume its resolved view and should not parse offer sets or pricing-experiment variants themselves.
101
+ Funnels should call `resolvePublishedBillingRuntime` once at their runtime-provider boundary. Screens consume its resolved view and should not parse offer sets or pricing-experiment variants themselves. Pass the resolved `stripePublishableKey` into shared Stripe checkout hooks so Stripe.js can load while the Checkout Session request is still in flight; the key returned by that request remains the compatibility fallback.
98
102
 
99
103
  ## Engineering Rules
100
104
 
@@ -51,6 +51,7 @@ export type SharedStripeCheckoutV2DialogProps = {
51
51
  walletButtonLabel: string;
52
52
  originalPriceLabel: string;
53
53
  originalPriceValue: string;
54
+ variant?: 'standard' | 'compact';
54
55
  };
55
56
  export type SharedCheckoutSpecialOfferDialogProps = {
56
57
  buttonColor: string;
@@ -63,5 +64,5 @@ export type SharedCheckoutSpecialOfferDialogProps = {
63
64
  themeColor: string;
64
65
  title: string;
65
66
  };
66
- export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
67
+ export declare function SharedStripeCheckoutV2Dialog({ checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, variant, ...props }: SharedStripeCheckoutV2DialogProps): import("react/jsx-runtime").JSX.Element;
67
68
  export declare function SharedCheckoutSpecialOfferDialog({ buttonColor, buttonLabel, description, discountLabel, imageAlt, imageSrc, onAccept, themeColor, title, }: SharedCheckoutSpecialOfferDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -40,6 +40,7 @@ const stripeCheckoutV2Appearance = {
40
40
  },
41
41
  },
42
42
  };
43
+ const compactStripeCheckoutV2Appearance = Object.assign(Object.assign({}, stripeCheckoutV2Appearance), { variables: Object.assign(Object.assign({}, stripeCheckoutV2Appearance.variables), { borderRadius: '14px', colorPrimary: '#1687f8' }) });
43
44
  const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
44
45
  const formatCountdown = (remainingSeconds) => {
45
46
  const normalizedSeconds = Number.isFinite(remainingSeconds)
@@ -59,7 +60,7 @@ function getFriendlyCardErrorMessage(error) {
59
60
  ? error.message
60
61
  : 'Payment failed. Please review your card details and try again.';
61
62
  }
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, }) {
63
+ 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, variant = 'standard', }) {
63
64
  const checkoutState = useCheckout();
64
65
  const walletPaymentMethods = usePlatformWalletPaymentMethods();
65
66
  const [selectedMethod, setSelectedMethod] = useState('wallet');
@@ -279,7 +280,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
279
280
  }
280
281
  };
281
282
  const visibleError = error;
282
- 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: [
283
+ return (_jsxs("div", { className: 'shared-checkout-v2-shell', "data-variant": variant, 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, variant === 'standard' ? (_jsxs("p", { className: 'shared-checkout-v2-satisfaction', children: [_jsx("strong", { children: satisfactionPercent }), " ", satisfactionLabel] })) : null, 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: [
283
284
  'shared-checkout-v2-total',
284
285
  showPromo ? '' : 'is-plain',
285
286
  ]
@@ -312,7 +313,7 @@ function SharedStripeCheckoutV2CheckoutSessionForm({ amountCents, buttonColor, c
312
313
  onCustomerEmailChange === null || onCustomerEmailChange === void 0 ? void 0 : onCustomerEmailChange(event.target.value);
313
314
  } }) })] }), _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] })] })] })] }));
314
315
  }
315
- function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry, stripePromise, }) {
316
+ function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry, stripePromise, variant, }) {
316
317
  const providerChildren = children;
317
318
  const checkoutProviderOptions = useMemo(() => (Object.assign(Object.assign({ clientSecret }, (fixedBillingCountry
318
319
  ? {
@@ -325,12 +326,14 @@ function CheckoutSessionProvider({ children, clientSecret, fixedBillingCountry,
325
326
  },
326
327
  }
327
328
  : {})), { elementsOptions: {
328
- appearance: stripeCheckoutV2Appearance,
329
- } })), [clientSecret, fixedBillingCountry]);
329
+ appearance: variant === 'compact'
330
+ ? compactStripeCheckoutV2Appearance
331
+ : stripeCheckoutV2Appearance,
332
+ } })), [clientSecret, fixedBillingCountry, variant]);
330
333
  return (_jsx(CheckoutProvider, { stripe: stripePromise, options: checkoutProviderOptions, children: providerChildren }, clientSecret));
331
334
  }
332
335
  export function SharedStripeCheckoutV2Dialog(_a) {
333
- var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries"]);
336
+ var { checkoutAnalytics, checkoutSessionId, clientSecret, onClose, stripePromise, supportedCountries, variant = 'standard' } = _a, props = __rest(_a, ["checkoutAnalytics", "checkoutSessionId", "clientSecret", "onClose", "stripePromise", "supportedCountries", "variant"]);
334
337
  const normalizedSupportedCountries = useMemo(() => normalizeSupportedCheckoutCountries(supportedCountries), [supportedCountries]);
335
338
  const fixedBillingCountry = getFixedSupportedBillingCountry(normalizedSupportedCountries);
336
339
  useEffect(() => {
@@ -348,7 +351,7 @@ export function SharedStripeCheckoutV2Dialog(_a) {
348
351
  window.addEventListener('keydown', handleKeyDown);
349
352
  return () => window.removeEventListener('keydown', handleKeyDown);
350
353
  }, [onClose]);
351
- 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 })] }));
354
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: 'shared-checkout-v2-overlay', children: _jsx("div", { className: 'shared-checkout-v2-dialog', "data-variant": variant, role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'shared-checkout-v2-title', children: _jsx(CheckoutSessionProvider, { clientSecret: clientSecret, fixedBillingCountry: fixedBillingCountry, stripePromise: stripePromise, variant: variant, children: _jsx(SharedStripeCheckoutV2CheckoutSessionForm, Object.assign({}, props, { checkoutAnalytics: checkoutAnalytics, checkoutSessionId: checkoutSessionId, clientSecret: clientSecret, onClose: onClose, supportedCountries: normalizedSupportedCountries, variant: variant })) }) }) }), _jsx("style", { children: sharedStripeCheckoutV2Styles })] }));
352
355
  }
353
356
  function SharedCheckoutSpecialOfferGift({ discountLabel, imageAlt, imageSrc, }) {
354
357
  if (imageSrc) {
@@ -383,6 +386,68 @@ const sharedStripeCheckoutV2Styles = `
383
386
  background: #fff;
384
387
  }
385
388
 
389
+ @media (min-width: 640px) {
390
+ .shared-checkout-v2-overlay:has(.shared-checkout-v2-dialog[data-variant='compact']) {
391
+ align-items: center;
392
+ padding: 24px;
393
+ background: rgb(0 0 0 / 48%);
394
+ }
395
+
396
+ .shared-checkout-v2-dialog[data-variant='compact'] {
397
+ width: min(100%, 520px);
398
+ height: auto;
399
+ max-height: calc(100svh - 48px);
400
+ border-radius: 24px;
401
+ box-shadow: 0 24px 70px rgb(0 0 0 / 28%);
402
+ }
403
+ }
404
+
405
+ .shared-checkout-v2-shell[data-variant='compact'] {
406
+ height: auto;
407
+ max-height: min(100svh, 760px);
408
+ }
409
+
410
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-header {
411
+ min-height: 88px;
412
+ padding: 0 72px;
413
+ }
414
+
415
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-header h2 {
416
+ font-size: 27px;
417
+ }
418
+
419
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-close {
420
+ right: 22px;
421
+ left: auto;
422
+ }
423
+
424
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-summary {
425
+ padding: 0 36px;
426
+ }
427
+
428
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-total {
429
+ min-height: 82px;
430
+ border: 1px solid #ececef;
431
+ border-radius: 16px;
432
+ padding: 0 22px;
433
+ background: #fbfbfc;
434
+ }
435
+
436
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-total svg {
437
+ display: none;
438
+ }
439
+
440
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-payment {
441
+ padding-right: 36px;
442
+ padding-left: 36px;
443
+ }
444
+
445
+ .shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-card-submit {
446
+ border-radius: 14px;
447
+ background: var(--shared-checkout-v2-button-color);
448
+ text-transform: none;
449
+ }
450
+
386
451
  .shared-checkout-v2-shell {
387
452
  height: 100%;
388
453
  max-height: 100svh;
@@ -13,6 +13,7 @@ export type StripeOneTimeCheckoutSessionInput = {
13
13
  plan?: StripeOneTimeCheckoutPlanInput | null;
14
14
  returnUrl: string;
15
15
  runtimeConfig?: StripeRuntimeConfigOverrides;
16
+ stripePublishableKey?: string | null;
16
17
  userId?: string | null;
17
18
  };
18
19
  export type StripeOneTimeCheckoutPreparationOptions = {
@@ -39,10 +40,10 @@ export type StripeOneTimeCheckoutSession = {
39
40
  stripePromise: Promise<Stripe | null> | null;
40
41
  };
41
42
  export declare const buildStripeOneTimeCheckoutPreparationAnalyticsMetadata: (analyticsMetadata: Record<string, unknown> | null | undefined, options?: StripeOneTimeCheckoutPreparationOptions) => Record<string, unknown> | null | undefined;
42
- export type StripeOneTimeCheckoutIntentKeyInput = Pick<StripeOneTimeCheckoutSessionInput, 'checkoutMode' | 'couponId' | 'customerEmail' | 'plan' | 'returnUrl' | 'runtimeConfig' | 'userId'> & {
43
+ export type StripeOneTimeCheckoutIntentKeyInput = Pick<StripeOneTimeCheckoutSessionInput, 'checkoutMode' | 'couponId' | 'customerEmail' | 'plan' | 'returnUrl' | 'runtimeConfig' | 'stripePublishableKey' | 'userId'> & {
43
44
  analyticsMetadata?: Record<string, unknown> | null;
44
45
  };
45
- export declare function buildStripeOneTimeCheckoutIntentKey({ checkoutMode, couponId, customerEmail, plan, returnUrl, runtimeConfig, userId, }: StripeOneTimeCheckoutIntentKeyInput): string;
46
+ export declare function buildStripeOneTimeCheckoutIntentKey({ checkoutMode, couponId, customerEmail, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }: StripeOneTimeCheckoutIntentKeyInput): string;
46
47
  export declare function shouldResetStripeOneTimeCheckoutSessionForIntentKey(previousIntentKey: string | null, nextIntentKey: string): boolean;
47
- export declare function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMode, couponId, customerEmail, enabled, onError, plan, returnUrl, runtimeConfig, userId, }: StripeOneTimeCheckoutSessionInput): StripeOneTimeCheckoutSession;
48
+ export declare function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMode, couponId, customerEmail, enabled, onError, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }: StripeOneTimeCheckoutSessionInput): StripeOneTimeCheckoutSession;
48
49
  export {};
@@ -36,13 +36,14 @@ export const buildStripeOneTimeCheckoutPreparationAnalyticsMetadata = (analytics
36
36
  const _b = analyticsMetadata !== null && analyticsMetadata !== void 0 ? analyticsMetadata : {}, { payment_method: _paymentMethod, paymentMethod: _camelCasePaymentMethod } = _b, metadata = __rest(_b, ["payment_method", "paymentMethod"]);
37
37
  return Object.assign(Object.assign(Object.assign({}, metadata), (checkoutStartSource ? { checkoutStartSource } : {})), (paymentMethod ? { payment_method: paymentMethod } : {}));
38
38
  };
39
- export function buildStripeOneTimeCheckoutIntentKey({ checkoutMode, couponId, customerEmail, plan, returnUrl, runtimeConfig, userId, }) {
39
+ export function buildStripeOneTimeCheckoutIntentKey({ checkoutMode, couponId, customerEmail, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }) {
40
40
  var _a;
41
41
  const runtimeConfigSignature = [
42
42
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
43
43
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId),
44
44
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelVersionId),
45
45
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey),
46
+ normalizeRuntimeConfigValue(stripePublishableKey),
46
47
  ].join('|');
47
48
  const planSignature = [
48
49
  normalizeRuntimeConfigValue(plan === null || plan === void 0 ? void 0 : plan.id),
@@ -65,7 +66,7 @@ export function buildStripeOneTimeCheckoutIntentKey({ checkoutMode, couponId, cu
65
66
  export function shouldResetStripeOneTimeCheckoutSessionForIntentKey(previousIntentKey, nextIntentKey) {
66
67
  return previousIntentKey !== null && previousIntentKey !== nextIntentKey;
67
68
  }
68
- export function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMode, couponId, customerEmail, enabled = true, onError, plan, returnUrl, runtimeConfig, userId, }) {
69
+ export function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMode, couponId, customerEmail, enabled = true, onError, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }) {
69
70
  var _a, _b, _c;
70
71
  const [clientSecret, setClientSecret] = useState(null);
71
72
  const [clientSecretIntentKey, setClientSecretIntentKey] = useState(null);
@@ -77,7 +78,8 @@ export function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMod
77
78
  const requestIdRef = useRef(0);
78
79
  const configured = enabled &&
79
80
  (isStripeConfigured(checkoutMode) ||
80
- Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)));
81
+ Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)) ||
82
+ Boolean(normalizeRuntimeConfigValue(stripePublishableKey)));
81
83
  const intentKey = buildStripeOneTimeCheckoutIntentKey({
82
84
  checkoutMode,
83
85
  couponId,
@@ -85,6 +87,7 @@ export function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMod
85
87
  plan,
86
88
  returnUrl,
87
89
  runtimeConfig,
90
+ stripePublishableKey,
88
91
  userId,
89
92
  });
90
93
  const planKey = [
@@ -94,7 +97,10 @@ export function useStripeOneTimeCheckoutSession({ analyticsMetadata, checkoutMod
94
97
  ].join('|');
95
98
  const activeClientSecret = clientSecretIntentKey === intentKey ? clientSecret : null;
96
99
  const activeCheckoutSessionId = clientSecretIntentKey === intentKey ? checkoutSessionId : null;
97
- const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey !== null && runtimeStripePublishableKey !== void 0 ? runtimeStripePublishableKey : runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey), [checkoutMode, runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey, runtimeStripePublishableKey]);
100
+ const stripePromise = useMemo(() => {
101
+ var _a;
102
+ return getStripePromise(checkoutMode, (_a = runtimeStripePublishableKey !== null && runtimeStripePublishableKey !== void 0 ? runtimeStripePublishableKey : stripePublishableKey) !== null && _a !== void 0 ? _a : runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey);
103
+ }, [checkoutMode, runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey, runtimeStripePublishableKey, stripePublishableKey]);
98
104
  const previousIntentKeyRef = useRef(intentKey);
99
105
  const analyticsMetadataRef = useRef(analyticsMetadata);
100
106
  useEffect(() => {
@@ -14,6 +14,7 @@ export type StripeSubscriptionCheckoutSessionInput = {
14
14
  plan?: PaywallPlan | null;
15
15
  returnUrl: string;
16
16
  runtimeConfig?: StripeRuntimeConfigOverrides;
17
+ stripePublishableKey?: string | null;
17
18
  userId?: string | null;
18
19
  };
19
20
  export type StripeSubscriptionCheckoutPreparationOptions = {
@@ -42,10 +43,10 @@ export type StripeSubscriptionCheckoutSession = {
42
43
  updateCheckoutSessionPlan: () => Promise<boolean>;
43
44
  };
44
45
  export declare const buildStripeSubscriptionCheckoutPreparationAnalyticsMetadata: (analyticsMetadata: Record<string, unknown> | null | undefined, options?: StripeSubscriptionCheckoutPreparationOptions) => Record<string, unknown> | null | undefined;
45
- export type StripeSubscriptionCheckoutIntentKeyInput = Pick<StripeSubscriptionCheckoutSessionInput, 'checkoutMode' | 'couponId' | 'customerEmail' | 'returnUrl' | 'runtimeConfig' | 'userId'> & {
46
+ export type StripeSubscriptionCheckoutIntentKeyInput = Pick<StripeSubscriptionCheckoutSessionInput, 'checkoutMode' | 'couponId' | 'customerEmail' | 'returnUrl' | 'runtimeConfig' | 'stripePublishableKey' | 'userId'> & {
46
47
  analyticsMetadata?: Record<string, unknown> | null;
47
48
  };
48
- export declare function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, userId, }: StripeSubscriptionCheckoutIntentKeyInput): string;
49
+ export declare function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, stripePublishableKey, userId, }: StripeSubscriptionCheckoutIntentKeyInput): string;
49
50
  export declare function shouldResetStripeSubscriptionCheckoutSessionForIntentKey(previousIntentKey: string | null, nextIntentKey: string): boolean;
50
51
  export declare function isInactiveCheckoutSessionError(message?: string | null): boolean;
51
- export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, couponId, customerEmail, displayPlan, enabled, onError, plan, returnUrl, runtimeConfig, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
52
+ export declare function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, couponId, customerEmail, displayPlan, enabled, onError, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }: StripeSubscriptionCheckoutSessionInput): StripeSubscriptionCheckoutSession;
@@ -35,12 +35,13 @@ export const buildStripeSubscriptionCheckoutPreparationAnalyticsMetadata = (anal
35
35
  const _b = analyticsMetadata !== null && analyticsMetadata !== void 0 ? analyticsMetadata : {}, { payment_method: _paymentMethod, paymentMethod: _camelCasePaymentMethod } = _b, metadata = __rest(_b, ["payment_method", "paymentMethod"]);
36
36
  return Object.assign(Object.assign(Object.assign({}, metadata), (checkoutStartSource ? { checkoutStartSource } : {})), (paymentMethod ? { payment_method: paymentMethod } : {}));
37
37
  };
38
- export function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, userId, }) {
38
+ export function buildStripeSubscriptionCheckoutIntentKey({ checkoutMode, couponId, customerEmail, returnUrl, runtimeConfig, stripePublishableKey, userId, }) {
39
39
  const runtimeConfigSignature = [
40
40
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
41
41
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId),
42
42
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelVersionId),
43
43
  normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey),
44
+ normalizeRuntimeConfigValue(stripePublishableKey),
44
45
  ].join('|');
45
46
  const customerEmailSignature = normalizeRuntimeConfigValue(customerEmail);
46
47
  const userIdSignature = normalizeRuntimeConfigValue(userId);
@@ -61,7 +62,7 @@ export function isInactiveCheckoutSessionError(message) {
61
62
  var _a;
62
63
  return /\bcheckout session\b.*\bno longer active\b/i.test((_a = message === null || message === void 0 ? void 0 : message.trim()) !== null && _a !== void 0 ? _a : '');
63
64
  }
64
- export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, couponId, customerEmail, displayPlan, enabled = true, onError, plan, returnUrl, runtimeConfig, userId, }) {
65
+ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMetadata, couponId, customerEmail, displayPlan, enabled = true, onError, plan, returnUrl, runtimeConfig, stripePublishableKey, userId, }) {
65
66
  var _a, _b, _c, _d, _e;
66
67
  const [clientSecret, setClientSecret] = useState(null);
67
68
  const [clientSecretIntentKey, setClientSecretIntentKey] = useState(null);
@@ -74,13 +75,15 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
74
75
  const requestIdRef = useRef(0);
75
76
  const configured = enabled &&
76
77
  (isStripeConfigured(checkoutMode) ||
77
- Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)));
78
+ Boolean(normalizeRuntimeConfigValue(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)) ||
79
+ Boolean(normalizeRuntimeConfigValue(stripePublishableKey)));
78
80
  const intentKey = buildStripeSubscriptionCheckoutIntentKey({
79
81
  checkoutMode,
80
82
  couponId,
81
83
  customerEmail,
82
84
  returnUrl,
83
85
  runtimeConfig,
86
+ stripePublishableKey,
84
87
  userId,
85
88
  });
86
89
  const planKey = [
@@ -93,7 +96,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
93
96
  const activeClientSecret = clientSecretIntentKey === intentKey ? clientSecret : null;
94
97
  const activeCheckoutSessionId = clientSecretIntentKey === intentKey ? checkoutSessionId : null;
95
98
  const activePlanKey = clientSecretIntentKey === intentKey ? clientSecretPlanKey : null;
96
- const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey), [checkoutMode, runtimeStripePublishableKey]);
99
+ const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey !== null && runtimeStripePublishableKey !== void 0 ? runtimeStripePublishableKey : stripePublishableKey), [checkoutMode, runtimeStripePublishableKey, stripePublishableKey]);
97
100
  const previousIntentKeyRef = useRef(intentKey);
98
101
  const analyticsMetadataRef = useRef(analyticsMetadata);
99
102
  useEffect(() => {
@@ -8,6 +8,7 @@ export type ResolvedPublishedBillingRuntime = {
8
8
  offerSetId: string;
9
9
  paymentProfileId: string | null;
10
10
  provider: 'stripe' | 'solidgate';
11
+ stripePublishableKey: string | null;
11
12
  experimentId: string | null;
12
13
  variantKey: string | null;
13
14
  experiments: readonly FunnelExperimentDefinition[];
@@ -2,7 +2,7 @@ import { resolveGeneratedOfferSetRuntime, resolvePublishedOfferSetSelection, res
2
2
  import { buildBillingDiscountCatalog } from './paywallOffer.service.js';
3
3
  import { buildConfigPaywallPlans, } from '../providers/stripe/services/stripe.service.js';
4
4
  export const resolvePublishedBillingRuntime = ({ config, featureFlags, mode, search = '', defaultOfferSetId, baseCatalogsByMode, fallbackDiscounts, resolvedExperiments = resolvePublishedRuntimeExperiments(config), }) => {
5
- var _a, _b, _c, _d;
5
+ var _a, _b, _c, _d, _e, _f, _g;
6
6
  const offerSets = (_a = config === null || config === void 0 ? void 0 : config.offerSets) !== null && _a !== void 0 ? _a : [];
7
7
  const selection = resolvePublishedOfferSetSelection({
8
8
  offerSets,
@@ -22,12 +22,17 @@ export const resolvePublishedBillingRuntime = ({ config, featureFlags, mode, sea
22
22
  .map((key) => planCatalog[key])
23
23
  .filter((plan) => Boolean(plan));
24
24
  const discountList = runtime.getDiscountList(mode);
25
+ const provider = runtime.getPaymentProvider(mode);
26
+ const paymentProviderConfig = (_c = (_b = runtime.offerSet) === null || _b === void 0 ? void 0 : _b.paymentProviderConfigByMode) === null || _c === void 0 ? void 0 : _c[mode];
25
27
  return {
26
- revisionId: (_b = config === null || config === void 0 ? void 0 : config.revisionId) !== null && _b !== void 0 ? _b : null,
28
+ revisionId: (_d = config === null || config === void 0 ? void 0 : config.revisionId) !== null && _d !== void 0 ? _d : null,
27
29
  mode,
28
30
  offerSetId: selection.offerSetId,
29
- paymentProfileId: ((_d = (_c = runtime.offerSet) === null || _c === void 0 ? void 0 : _c.paymentProfileId) === null || _d === void 0 ? void 0 : _d.trim()) || null,
30
- provider: runtime.getPaymentProvider(mode),
31
+ paymentProfileId: ((_f = (_e = runtime.offerSet) === null || _e === void 0 ? void 0 : _e.paymentProfileId) === null || _f === void 0 ? void 0 : _f.trim()) || null,
32
+ provider,
33
+ stripePublishableKey: provider === 'stripe' && (paymentProviderConfig === null || paymentProviderConfig === void 0 ? void 0 : paymentProviderConfig.provider) === 'stripe'
34
+ ? ((_g = paymentProviderConfig === null || paymentProviderConfig === void 0 ? void 0 : paymentProviderConfig.stripePublishableKey) === null || _g === void 0 ? void 0 : _g.trim()) || null
35
+ : null,
31
36
  experimentId: selection.experimentId,
32
37
  variantKey: selection.variantKey,
33
38
  experiments: resolvedExperiments.experiments,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.7.20",
3
+ "version": "0.7.22",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",
@@ -32,8 +32,8 @@
32
32
  "test:run": "vitest run --passWithNoTests"
33
33
  },
34
34
  "dependencies": {
35
- "@funnelsgrove/analytics": "^0.1.78",
36
- "@funnelsgrove/runtime": "^0.7.29",
35
+ "@funnelsgrove/analytics": "^0.1.79",
36
+ "@funnelsgrove/runtime": "^0.7.30",
37
37
  "@solidgate/react-sdk": "1.34.0",
38
38
  "@stripe/react-stripe-js": "^5.6.0",
39
39
  "@stripe/stripe-js": "^8.7.0",