@funnelsgrove/payments 0.1.46 → 0.1.48

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
@@ -2,70 +2,88 @@
2
2
 
3
3
  Shared billing and checkout helpers for funnels.
4
4
 
5
- Detailed implementation docs:
5
+ Read this file before editing checkout code. Deeper implementation docs:
6
6
 
7
7
  - [Shared Payments](../../docs/funnel-sdk/shared-payments.md)
8
- - [Funnel API payment endpoints](../../docs/funnel-sdk/funnel-api.md#checkout-endpoints)
8
+ - [Funnel SDK runtime service](../../docs/funnel-sdk/funnel-api.md)
9
9
 
10
- ## Build And Publish
10
+ ## Owns provider-backed checkout primitives
11
11
 
12
- - Build distributable output with `npm run build --workspace @funnelsgrove/payments`.
13
- - Publish from the repo root with `npm publish --workspace @funnelsgrove/payments --access public`.
14
- - The package pins `@funnelsgrove/runtime` to the same exact version and the build resolves against the runtime package's emitted `dist` contract.
15
- - The build normalizes generated relative ESM imports to explicit `.js` files for published package consumers.
12
+ `@funnelsgrove/payments` owns reusable payment contracts, provider adapters, checkout-session helpers, wallet slots, and checkout UI primitives. Funnel code owns paywall layout, copy, when an offer opens, post-payment navigation, and funnel-specific analytics timing.
16
13
 
17
- ## Use This Package For
14
+ ## Current Checkout Path
18
15
 
19
- - Stripe plan loading and checkout integration
20
- - global funnel billing catalog contracts
21
- - reusable plan-selector UI
22
- - reusable shared embedded checkout dialogs
23
- - reusable Stripe Express Checkout wrappers for funnels that need native Apple Pay or Google Pay controls outside the shared dialogs
24
- - provider-ready checkout session primitives that keep paywalls from owning provider SDK setup, client-secret preparation, or wallet-button replacement logic
25
- - compatibility exports for saved builder paywall drafts, including the Apple Pay subscribe fallback button
26
- - billing catalog types and runtime helpers
27
- - reusable paywall offer helpers for timed discounts, discounted display plans, promo labels, and renewal disclaimer text
16
+ Use these for new subscription paywalls:
17
+
18
+ - `useStripeSubscriptionCheckoutSession`
19
+ - `SharedStripeCheckoutV2Dialog`
20
+ - `ApplePaySubscriptionCheckoutSlot`
21
+ - `GooglePaySubscriptionCheckoutSlot`
22
+ - `WalletSubscriptionCheckoutSlot`
23
+ - `trackPaidStripeSubscriptionCheckoutCompleted`
24
+
25
+ Use `chargeStripeOneClickPayment` for post-checkout one-click upsells when the shared client helper fits the funnel. It delegates to `funnelSdkService.chargeOneClickPayment`.
26
+
27
+ ## Compatibility-Only Surfaces
28
28
 
29
- ## Responsibilities
29
+ Keep these exports available for saved drafts, old published artifacts, and controlled migrations. Do not use them for new subscription checkout work:
30
30
 
31
- - keep paywall behavior consistent across funnels
32
- - define the shared billing types used by funnel-local catalogs
33
- - expose one ordered funnel-local billing catalog contract
34
- - keep the public checkout identity contract aligned on `user_id` for payment intents and any remaining hosted-checkout fallbacks
35
- - keep reusable discount math and display-plan shaping out of funnel step files
36
- - keep provider-specific implementation under `src/providers/<provider>` so funnels can consume stable payment slots while future providers add their own adapters
31
+ - `createStripePaymentIntent`
32
+ - `SharedStripeCheckoutDialog`
33
+ - `ApplePaySubscribeButton`
34
+ - `GooglePaySubscribeButton`
35
+ - `APPLE_PAY_QR_CODE_URL`
37
36
 
38
- ## What Belongs Here
37
+ When a live funnel still uses one of these, migrate the funnel deliberately with its own tests before removing the export.
38
+
39
+ ## Use This Package For
39
40
 
40
41
  - billing catalog types and normalization helpers
41
- - Stripe SDK wiring
42
- - shared checkout/plan-selector components
43
- - generic paywall offer helpers that accept funnel-provided plans and discount catalogs
44
- - the default embedded Stripe checkout dialog UX that funnels can feed with their own copy, pricing summary rows, guarantee note, and an optional editable customer email that is committed before card or wallet confirmation
45
- - the `StripeExpressCheckoutElement` wrapper, which keeps `Elements` provider ownership inside this package so catalog funnels with their own dependency installs do not pass Stripe promises across duplicate local Stripe type copies
46
- - `src/providers/paymentProvider.types.ts` for provider-neutral checkout preparation state and provider ids
47
- - `src/providers/stripe/useStripeSubscriptionCheckoutSession.ts` for Stripe SDK initialization, publishable-key resolution, subscription client-secret preparation, card/wallet loading state, and friendly checkout errors
48
- - `src/providers/stripe/ApplePaySubscriptionCheckoutSlot.tsx` and `src/providers/stripe/GooglePaySubscriptionCheckoutSlot.tsx` for wallet shells that prepare Stripe Express Checkout on load, keep the loading placeholder clickable, and let Stripe's real wallet controls sit above the placeholder as soon as they mount
49
- - Stripe subscription checkout sessions reuse the active client secret across card checkout and paywall wallet checkout for the same intent key, so opening the embedded checkout after a paywall wallet button is ready does not create a second subscription session.
50
- - `trackPaidStripeSubscriptionCheckoutCompleted` verifies a Stripe custom Checkout Session is paid before delegating to `@funnelsgrove/analytics` for the canonical `checkout_completed` purchase event.
51
- - Stripe Express Checkout elements must stay mounted and measurable until Stripe reports availability; only hide the container after `onReady` or `onLoadError` reports that the requested wallet method is unavailable.
52
- - Shared checkout dialogs must switch to card checkout when Stripe reports no requested wallet availability, so an unavailable Apple Pay or Google Pay shell never leaves a fake wallet tab blocking the card form.
53
- - Wallet slots should not leave disabled grey placeholder shells blocking the paywall. While availability is unknown, the placeholder can sit behind Stripe's real wallet element; after Stripe reports unavailable or preparation cannot create a client secret, the placeholder must disappear instead of opening a card checkout under wallet branding.
54
- - Checkout v2 owns only real Stripe Elements for card and wallet collection: Stripe controls the card-field placeholders, Stripe's `ExpressCheckoutElement` controls Apple Pay / Google Pay availability, desktop web can expose both wallet icons, and mobile narrows to Apple Pay on iOS or Google Pay on Android.
55
- - Checkout v2 can receive a paywall-confirmed wallet availability hint and seed its wallet tab from that state, letting a checkout reopen keep Apple Pay or Google Pay visible while its own Express Checkout element remounts against the same client secret.
56
- - Checkout v2 renders the wallet tab icons from the active platform wallet list and keeps Apple Pay / Google Pay marks large enough to read inside the tab.
57
- - Checkout v2 keeps the fixed mobile dialog viewport-bound and scrolls the inner checkout shell so card fields, wallet controls, trust copy, and bottom actions remain reachable on short screens.
58
- - Checkout v2 renders an editable email field when a funnel opens card checkout without a stored customer email, so direct preview paywall QA can complete Stripe confirmation instead of failing validation invisibly.
59
- - The shared special-offer dialog can render a funnel-provided gift image while keeping the discount label overlaid and retaining the inline SVG fallback for funnels without a custom asset.
60
- - the shared large-format Apple Pay and Google Pay subscribe CTAs, QR-code handoff link support, and the compact Visa / Mastercard / G Pay / Apple Pay image row used by the embedded checkout shell trust footer
61
- - the Google Pay fallback CTA uses the downloaded Google Pay `G` mark paths, keeps at least 8px clear space, and matches Apple Pay's roughly 27px rendered subscribe text size until Stripe replaces it with the real wallet control
62
-
63
- ## What Does Not Belong Here
42
+ - runtime-mode-aware plan catalog selection
43
+ - Stripe SDK and public payment API client helpers
44
+ - subscription checkout-session preparation, reuse, update, and recovery
45
+ - reusable plan-selector UI
46
+ - shared embedded checkout dialogs
47
+ - Stripe Express Checkout wallet slots and lower-level wallet primitives
48
+ - generic timed-offer display helpers
49
+ - checkout completion analytics handoff to `@funnelsgrove/analytics`
50
+
51
+ ## Do Not Use This Package For
64
52
 
65
53
  - funnel routing
66
- - funnel-owned analytics event definitions outside the shared checkout completion handoff
67
- - funnel-owned step layout outside the shared checkout shell
68
- - funnel-owned billing catalog entries
69
- - funnel-specific decisions about when to activate or upgrade an offer
70
54
  - manifest validation
55
+ - funnel-owned billing catalog entries
56
+ - funnel-specific paywall layout or copy
57
+ - funnel-specific decisions about when to activate, upgrade, or recover an offer
58
+ - analytics transport internals
71
59
  - direct provider SDK calls inside funnel paywall steps; add provider adapters here first, then wire the funnel to the shared session or slot
60
+
61
+ ## Public Surfaces
62
+
63
+ - `config/billing.config`: billing catalog, mapping, plan, and discount contracts.
64
+ - `services/planCatalog.service`: plan resolution and selection helpers.
65
+ - `services/runtimeBillingPlanCatalog.service`: test/live runtime catalog selection.
66
+ - `services/paywallOffer.service`: timed discount and display-plan helpers.
67
+ - `services/stripe.service`: Stripe loader, checkout-session, hosted checkout, one-click, and compatibility PaymentIntent clients.
68
+ - `providers/*`: provider-neutral checkout state and Stripe subscription checkout slots.
69
+ - `components/shared/*`: plan selector, checkout dialogs, Express Checkout wrappers, wallet placeholders, and trust assets.
70
+ - `testing/walletCheckoutSmoke`: wallet checkout smoke assertions.
71
+
72
+ ## Engineering Rules
73
+
74
+ - Keep provider-specific implementation under `src/providers/<provider>`.
75
+ - Stripe owns real card fields and wallet controls. Local wallet buttons are placeholders until Stripe confirms availability.
76
+ - Wallet unavailable state must fall back to card/manual checkout or disappear.
77
+ - Do not create checkout sessions until the visitor taps a visible checkout CTA.
78
+ - Keep discount math reusable here, but keep offer activation timing in funnel code.
79
+ - Checkout metadata must avoid sensitive raw query params and use `@funnelsgrove/analytics` metadata helpers.
80
+
81
+ ## Build, Test, Publish
82
+
83
+ ```bash
84
+ npm run test:run --workspace @funnelsgrove/payments
85
+ npm run build --workspace @funnelsgrove/payments
86
+ npm publish --workspace @funnelsgrove/payments --access public
87
+ ```
88
+
89
+ The build normalizes generated relative ESM imports to explicit `.js` files for published package consumers.
package/dist/index.d.ts CHANGED
@@ -13,13 +13,13 @@ export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
13
13
  export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
14
14
  export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
15
15
  export { ManageSubscriptionScreen, type ManageSubscriptionContent, type ManageSubscriptionScreenProps, } from './components/ManageSubscriptionScreen.js';
16
- export * from './components/shared/SharedStripeCheckoutDialog.js';
17
16
  export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
18
- export * from './components/shared/ApplePaySubscribeButton.js';
19
- export * from './components/shared/GooglePaySubscribeButton.js';
20
- export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
21
- export * from './components/shared/StripeExpressCheckoutButton.js';
22
17
  export * from './components/shared/StripeExpressCheckoutElement.js';
23
18
  export * from './components/shared/StripePlanSelector.js';
24
19
  export * from './components/shared/walletPlatform.js';
20
+ export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
21
+ export * from './components/shared/StripeExpressCheckoutButton.js';
22
+ export * from './components/shared/SharedStripeCheckoutDialog.js';
23
+ export * from './components/shared/ApplePaySubscribeButton.js';
24
+ export * from './components/shared/GooglePaySubscribeButton.js';
25
25
  export * from './testing/walletCheckoutSmoke.js';
package/dist/index.js CHANGED
@@ -1,25 +1,31 @@
1
+ // Billing contracts and plan resolution.
1
2
  export * from './config/billing.config.js';
2
3
  export * from './services/preview-frame.service.js';
3
4
  export * from './services/runtime-mode.service.js';
4
5
  export * from './services/planCatalog.service.js';
5
6
  export * from './services/runtimeBillingPlanCatalog.service.js';
6
7
  export * from './services/paywallOffer.service.js';
8
+ // Stripe API clients and checkout completion handoff.
7
9
  export * from './services/stripe.service.js';
8
10
  export * from './services/checkoutCompletionAnalytics.service.js';
9
11
  export * from './hooks/useResolvedPaywallPlans.js';
12
+ // Provider-neutral and Stripe subscription checkout primitives.
10
13
  export * from './providers/paymentProvider.types.js';
11
14
  export * from './providers/stripe/useStripeSubscriptionCheckoutSession.js';
12
15
  export * from './providers/stripe/WalletSubscriptionCheckoutSlot.js';
13
16
  export * from './providers/stripe/ApplePaySubscriptionCheckoutSlot.js';
14
17
  export * from './providers/stripe/GooglePaySubscriptionCheckoutSlot.js';
18
+ // Shared checkout and subscription-management UI.
15
19
  export { ManageSubscriptionScreen, } from './components/ManageSubscriptionScreen.js';
16
- export * from './components/shared/SharedStripeCheckoutDialog.js';
17
20
  export * from './components/shared/SharedStripeCheckoutV2Dialog.js';
18
- export * from './components/shared/ApplePaySubscribeButton.js';
19
- export * from './components/shared/GooglePaySubscribeButton.js';
20
- export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
21
- export * from './components/shared/StripeExpressCheckoutButton.js';
22
21
  export * from './components/shared/StripeExpressCheckoutElement.js';
23
22
  export * from './components/shared/StripePlanSelector.js';
24
23
  export * from './components/shared/walletPlatform.js';
24
+ export * from './components/shared/StripeCheckoutExpressCheckoutButton.js';
25
+ export * from './components/shared/StripeExpressCheckoutButton.js';
26
+ // Compatibility-only surfaces kept for saved drafts and published artifacts.
27
+ export * from './components/shared/SharedStripeCheckoutDialog.js';
28
+ export * from './components/shared/ApplePaySubscribeButton.js';
29
+ export * from './components/shared/GooglePaySubscribeButton.js';
30
+ // QA helpers.
25
31
  export * from './testing/walletCheckoutSmoke.js';
@@ -1,6 +1,6 @@
1
1
  import { type Stripe } from '@stripe/stripe-js';
2
2
  import { type BillingFallbackPlanConfig, type BillingPlanCatalog, type BillingPlanInterval, type BillingPlanInputCatalog } from '../config/billing.config.js';
3
- import { type ResolvedCountryPricing } from '@funnelsgrove/runtime';
3
+ import { type FunnelSdkRuntimeConfigOverrides, type ResolvedCountryPricing } from '@funnelsgrove/runtime';
4
4
  import type { RuntimeMode } from '@funnelsgrove/runtime';
5
5
  import { type RemoteProjectBillingPlan } from './planCatalog.service.js';
6
6
  export type PaywallPlan = {
@@ -22,12 +22,7 @@ export type PaywallPlan = {
22
22
  billingIntervalCount?: number;
23
23
  source: 'stripe' | 'config';
24
24
  };
25
- export type StripeRuntimeConfigOverrides = {
26
- apiBaseUrl?: string | null;
27
- funnelId?: string | null;
28
- funnelVersionId?: string | null;
29
- funnelSdkPublishableKey?: string | null;
30
- };
25
+ export type StripeRuntimeConfigOverrides = FunnelSdkRuntimeConfigOverrides;
31
26
  export type PaywallPlanResolutionOptions = {
32
27
  locale?: string | null;
33
28
  pricing?: ResolvedCountryPricing<string> | null;
@@ -1,7 +1,7 @@
1
1
  var _a, _b, _c, _d;
2
2
  import { loadStripe } from '@stripe/stripe-js';
3
3
  import { billingPlanList, } from '../config/billing.config.js';
4
- import { buildMainApiUrl, buildSdkHeaders, FUNNEL_ID, FUNNEL_SDK_PUBLISHABLE_KEY, resolvePreviewPaymentPublishableKey, runtimeEnvConfig, } from '@funnelsgrove/runtime';
4
+ import { FUNNEL_ID, FUNNEL_SDK_PUBLISHABLE_KEY, funnelSdkService, runtimeEnvConfig, } from '@funnelsgrove/runtime';
5
5
  import { isBillingPlanMappingCatalog, resolveMappedProjectPlans, } from './planCatalog.service.js';
6
6
  const STRIPE_TEST_PUBLISHABLE_KEY = ((_b = (_a = runtimeEnvConfig.stripeTestPublishableKey) !== null && _a !== void 0 ? _a : runtimeEnvConfig.stripePublishableKey) !== null && _b !== void 0 ? _b : '').trim();
7
7
  const STRIPE_LIVE_PUBLISHABLE_KEY = ((_d = (_c = runtimeEnvConfig.stripeLivePublishableKey) !== null && _c !== void 0 ? _c : runtimeEnvConfig.stripePublishableKey) !== null && _d !== void 0 ? _d : '').trim();
@@ -26,35 +26,6 @@ const asTrimmedStringOrNull = (value) => {
26
26
  const trimmed = value.trim();
27
27
  return trimmed || null;
28
28
  };
29
- const trimTrailingSlash = (value) => {
30
- return value.replace(/\/+$/, '');
31
- };
32
- const toNormalizedPath = (path) => {
33
- return path.startsWith('/') ? path : `/${path}`;
34
- };
35
- const resolveStripeRuntimeConfig = (runtimeConfig) => {
36
- var _a, _b, _c;
37
- return {
38
- apiBaseUrl: asTrimmedStringOrNull(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.apiBaseUrl),
39
- funnelId: (_a = asTrimmedStringOrNull(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelId)) !== null && _a !== void 0 ? _a : asTrimmedStringOrNull(FUNNEL_ID),
40
- funnelVersionId: (_b = asTrimmedStringOrNull(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelVersionId)) !== null && _b !== void 0 ? _b : asTrimmedStringOrNull(runtimeEnvConfig.funnelVersionId),
41
- funnelSdkPublishableKey: resolvePreviewPaymentPublishableKey((_c = asTrimmedStringOrNull(runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey)) !== null && _c !== void 0 ? _c : asTrimmedStringOrNull(FUNNEL_SDK_PUBLISHABLE_KEY)) || null,
42
- };
43
- };
44
- const buildStripeRuntimeApiUrl = (path, runtimeConfig) => {
45
- const { apiBaseUrl } = resolveStripeRuntimeConfig(runtimeConfig);
46
- if (!apiBaseUrl) {
47
- return buildMainApiUrl(path);
48
- }
49
- return `${trimTrailingSlash(apiBaseUrl)}${toNormalizedPath(path)}`;
50
- };
51
- const buildStripeRuntimeHeaders = (runtimeConfig, headers) => {
52
- const { funnelSdkPublishableKey } = resolveStripeRuntimeConfig(runtimeConfig);
53
- if (!funnelSdkPublishableKey) {
54
- return Object.assign({}, (headers !== null && headers !== void 0 ? headers : {}));
55
- }
56
- return Object.assign({ 'x-sdk-publishable-key': funnelSdkPublishableKey }, (headers !== null && headers !== void 0 ? headers : {}));
57
- };
58
29
  const asFiniteNumberOrNull = (value) => {
59
30
  if (typeof value !== 'number' || !Number.isFinite(value)) {
60
31
  return null;
@@ -329,28 +300,6 @@ const toFallbackPaywallPlans = (planCatalog, options) => {
329
300
  const isFallbackBillingPlanCatalog = (planCatalog) => {
330
301
  return Array.isArray(planCatalog) || !isBillingPlanMappingCatalog(planCatalog);
331
302
  };
332
- const parseErrorMessage = async (response, fallbackMessage) => {
333
- try {
334
- const payload = (await response.json());
335
- const apiError = asTrimmedStringOrNull(payload.error);
336
- if (apiError) {
337
- return apiError;
338
- }
339
- }
340
- catch (_a) {
341
- // ignore JSON parsing errors
342
- }
343
- try {
344
- const errorText = await response.text();
345
- if (errorText.trim()) {
346
- return errorText;
347
- }
348
- }
349
- catch (_b) {
350
- // ignore text parsing errors
351
- }
352
- return fallbackMessage;
353
- };
354
303
  export function getFallbackPlans(planCatalog, options) {
355
304
  if (!planCatalog) {
356
305
  return reorderPlans(fallbackPaywallPlans, options === null || options === void 0 ? void 0 : options.pricing);
@@ -431,20 +380,9 @@ const getStripeSyncedPlanRecords = async (mode) => {
431
380
  return cachedPromise;
432
381
  }
433
382
  const nextPromise = (async () => {
434
- const url = new URL(buildMainApiUrl('/sdk/public/payments/plans'));
435
- url.searchParams.set('environment', mode);
436
- if (FUNNEL_ID) {
437
- url.searchParams.set('funnelId', FUNNEL_ID);
438
- }
439
- const response = await fetch(url.toString(), {
440
- method: 'GET',
441
- headers: buildSdkHeaders(),
383
+ const payload = await funnelSdkService.listPaymentPlans({
384
+ environment: mode,
442
385
  });
443
- if (!response.ok) {
444
- const errorMessage = await parseErrorMessage(response, 'Unable to load Stripe plans');
445
- throw new Error(errorMessage);
446
- }
447
- const payload = (await response.json());
448
386
  const rawPlans = Array.isArray(payload.plans) ? payload.plans : [];
449
387
  return rawPlans
450
388
  .filter((rawPlan) => isRecord(rawPlan))
@@ -595,58 +533,30 @@ const normalizeCheckoutAnalyticsMetadata = (metadata, plan) => {
595
533
  };
596
534
  export async function createStripePaymentIntent(input) {
597
535
  var _a, _b;
598
- const runtimeConfig = resolveStripeRuntimeConfig(input.runtimeConfig);
599
- const response = await fetch(buildStripeRuntimeApiUrl('/sdk/public/payments/intents', runtimeConfig), {
600
- method: 'POST',
601
- headers: buildStripeRuntimeHeaders(runtimeConfig, {
602
- 'Content-Type': 'application/json',
603
- }),
604
- body: JSON.stringify({
605
- publishableKey: runtimeConfig.funnelSdkPublishableKey || undefined,
606
- funnelId: runtimeConfig.funnelId || undefined,
607
- funnelVersionId: runtimeConfig.funnelVersionId || undefined,
608
- planId: input.planId,
609
- amountCents: input.amountCents,
610
- couponId: ((_a = input.couponId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
611
- analyticsMetadata: normalizeAnalyticsMetadata(input.analyticsMetadata),
612
- user_id: ((_b = input.user_id) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
613
- environment: input.environment || undefined,
614
- }),
536
+ return funnelSdkService.createOneTimePaymentIntent({
537
+ planId: input.planId,
538
+ amountCents: input.amountCents,
539
+ couponId: ((_a = input.couponId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
540
+ analyticsMetadata: normalizeAnalyticsMetadata(input.analyticsMetadata),
541
+ userId: ((_b = input.user_id) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
542
+ environment: input.environment,
543
+ runtimeConfig: input.runtimeConfig,
615
544
  });
616
- if (!response.ok) {
617
- const errorMessage = await parseErrorMessage(response, 'Unable to create payment intent');
618
- throw new Error(errorMessage);
619
- }
620
- return (await response.json());
621
545
  }
622
546
  export async function chargeStripeOneClickPayment(input) {
623
547
  var _a, _b, _c, _d, _e;
624
- const runtimeConfig = resolveStripeRuntimeConfig(input.runtimeConfig);
625
- const response = await fetch(buildStripeRuntimeApiUrl('/sdk/public/payments/one-click', runtimeConfig), {
626
- method: 'POST',
627
- headers: buildStripeRuntimeHeaders(runtimeConfig, {
628
- 'Content-Type': 'application/json',
629
- }),
630
- body: JSON.stringify({
631
- publishableKey: runtimeConfig.funnelSdkPublishableKey || undefined,
632
- funnelId: runtimeConfig.funnelId || undefined,
633
- funnelVersionId: runtimeConfig.funnelVersionId || undefined,
634
- planId: input.planId,
635
- amountCents: input.amountCents,
636
- currency: ((_a = input.currency) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
637
- analyticsMetadata: normalizeAnalyticsMetadata(input.analyticsMetadata),
638
- user_id: ((_b = input.user_id) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
639
- stripe_customer_id: ((_c = input.stripe_customer_id) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
640
- checkoutSessionId: ((_d = input.checkoutSessionId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
641
- idempotencyKey: ((_e = input.idempotencyKey) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
642
- environment: input.environment || undefined,
643
- }),
548
+ return funnelSdkService.chargeOneClickPayment({
549
+ planId: input.planId,
550
+ amountCents: input.amountCents,
551
+ currency: ((_a = input.currency) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
552
+ analyticsMetadata: normalizeAnalyticsMetadata(input.analyticsMetadata),
553
+ userId: ((_b = input.user_id) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
554
+ stripeCustomerId: ((_c = input.stripe_customer_id) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
555
+ checkoutSessionId: ((_d = input.checkoutSessionId) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
556
+ idempotencyKey: ((_e = input.idempotencyKey) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
557
+ environment: input.environment,
558
+ runtimeConfig: input.runtimeConfig,
644
559
  });
645
- if (!response.ok) {
646
- const errorMessage = await parseErrorMessage(response, 'Unable to charge one-click payment');
647
- throw new Error(errorMessage);
648
- }
649
- return (await response.json());
650
560
  }
651
561
  export async function createStripeSubscriptionCheckout(input) {
652
562
  var _a, _b, _c, _d, _e;
@@ -654,36 +564,22 @@ export async function createStripeSubscriptionCheckout(input) {
654
564
  if (!recurring) {
655
565
  throw new Error('Unable to resolve the recurring interval for the selected plan');
656
566
  }
657
- const runtimeConfig = resolveStripeRuntimeConfig(input.runtimeConfig);
658
- const response = await fetch(buildStripeRuntimeApiUrl('/sdk/public/payments/subscriptions', runtimeConfig), {
659
- method: 'POST',
660
- headers: buildStripeRuntimeHeaders(runtimeConfig, {
661
- 'Content-Type': 'application/json',
662
- }),
663
- body: JSON.stringify({
664
- publishableKey: runtimeConfig.funnelSdkPublishableKey || undefined,
665
- funnelId: runtimeConfig.funnelId || undefined,
666
- funnelVersionId: runtimeConfig.funnelVersionId || undefined,
667
- planId: getPaywallPlanSelectionValue(input.plan),
668
- providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
669
- title: input.plan.title,
670
- description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
671
- amountCents: input.plan.amountCents,
672
- billingInterval: recurring.interval,
673
- billingIntervalCount: recurring.intervalCount,
674
- couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
675
- analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
676
- customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
677
- returnUrl: input.returnUrl,
678
- user_id: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
679
- environment: input.environment || undefined,
680
- }),
567
+ return funnelSdkService.createSubscriptionCheckout({
568
+ planId: getPaywallPlanSelectionValue(input.plan),
569
+ providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
570
+ title: input.plan.title,
571
+ description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
572
+ amountCents: input.plan.amountCents,
573
+ billingInterval: recurring.interval,
574
+ billingIntervalCount: recurring.intervalCount,
575
+ couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
576
+ analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
577
+ customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
578
+ returnUrl: input.returnUrl,
579
+ userId: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
580
+ environment: input.environment,
581
+ runtimeConfig: input.runtimeConfig,
681
582
  });
682
- if (!response.ok) {
683
- const errorMessage = await parseErrorMessage(response, 'Unable to create subscription checkout');
684
- throw new Error(errorMessage);
685
- }
686
- return (await response.json());
687
583
  }
688
584
  export async function updateStripeSubscriptionCheckoutPlan(input) {
689
585
  var _a, _b, _c, _d, _e;
@@ -691,61 +587,33 @@ export async function updateStripeSubscriptionCheckoutPlan(input) {
691
587
  if (!recurring) {
692
588
  throw new Error('Unable to resolve the recurring interval for the selected plan');
693
589
  }
694
- const runtimeConfig = resolveStripeRuntimeConfig(input.runtimeConfig);
695
- const response = await fetch(buildStripeRuntimeApiUrl('/sdk/public/payments/subscriptions/update-plan', runtimeConfig), {
696
- method: 'POST',
697
- headers: buildStripeRuntimeHeaders(runtimeConfig, {
698
- 'Content-Type': 'application/json',
699
- }),
700
- body: JSON.stringify({
701
- publishableKey: runtimeConfig.funnelSdkPublishableKey || undefined,
702
- funnelId: runtimeConfig.funnelId || undefined,
703
- funnelVersionId: runtimeConfig.funnelVersionId || undefined,
704
- checkoutSessionId: input.checkoutSessionId.trim(),
705
- planId: getPaywallPlanSelectionValue(input.plan),
706
- providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
707
- title: input.plan.title,
708
- description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
709
- amountCents: input.plan.amountCents,
710
- billingInterval: recurring.interval,
711
- billingIntervalCount: recurring.intervalCount,
712
- couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
713
- analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
714
- customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
715
- user_id: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
716
- environment: input.environment || undefined,
717
- }),
590
+ return funnelSdkService.updateSubscriptionCheckoutPlan({
591
+ checkoutSessionId: input.checkoutSessionId.trim(),
592
+ planId: getPaywallPlanSelectionValue(input.plan),
593
+ providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
594
+ title: input.plan.title,
595
+ description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
596
+ amountCents: input.plan.amountCents,
597
+ billingInterval: recurring.interval,
598
+ billingIntervalCount: recurring.intervalCount,
599
+ couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
600
+ analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
601
+ customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
602
+ userId: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
603
+ environment: input.environment,
604
+ runtimeConfig: input.runtimeConfig,
718
605
  });
719
- if (!response.ok) {
720
- const errorMessage = await parseErrorMessage(response, 'Unable to update subscription checkout');
721
- throw new Error(errorMessage);
722
- }
723
- return (await response.json());
724
606
  }
725
607
  export async function verifyStripeSubscriptionCheckoutPayment(input) {
726
608
  const checkoutSessionId = input.checkoutSessionId.trim();
727
609
  if (!checkoutSessionId) {
728
610
  throw new Error('checkoutSessionId is required');
729
611
  }
730
- const runtimeConfig = resolveStripeRuntimeConfig(input.runtimeConfig);
731
- const response = await fetch(buildStripeRuntimeApiUrl('/sdk/public/payments/subscriptions/checkout-session-status', runtimeConfig), {
732
- method: 'POST',
733
- headers: buildStripeRuntimeHeaders(runtimeConfig, {
734
- 'Content-Type': 'application/json',
735
- }),
736
- body: JSON.stringify({
737
- publishableKey: runtimeConfig.funnelSdkPublishableKey || undefined,
738
- funnelId: runtimeConfig.funnelId || undefined,
739
- funnelVersionId: runtimeConfig.funnelVersionId || undefined,
740
- checkoutSessionId,
741
- environment: input.environment || undefined,
742
- }),
612
+ return funnelSdkService.verifySubscriptionCheckout({
613
+ checkoutSessionId,
614
+ environment: input.environment,
615
+ runtimeConfig: input.runtimeConfig,
743
616
  });
744
- if (!response.ok) {
745
- const errorMessage = await parseErrorMessage(response, 'Unable to verify subscription checkout');
746
- throw new Error(errorMessage);
747
- }
748
- return (await response.json());
749
617
  }
750
618
  export async function createStripeCheckoutSession(input) {
751
619
  var _a, _b, _c, _d, _e;
@@ -753,37 +621,23 @@ export async function createStripeCheckoutSession(input) {
753
621
  if (!recurring) {
754
622
  throw new Error('Unable to resolve the recurring interval for the selected plan');
755
623
  }
756
- const runtimeConfig = resolveStripeRuntimeConfig(input.runtimeConfig);
757
- const response = await fetch(buildStripeRuntimeApiUrl('/sdk/public/payments/checkout-session', runtimeConfig), {
758
- method: 'POST',
759
- headers: buildStripeRuntimeHeaders(runtimeConfig, {
760
- 'Content-Type': 'application/json',
761
- }),
762
- body: JSON.stringify({
763
- publishableKey: runtimeConfig.funnelSdkPublishableKey || undefined,
764
- funnelId: runtimeConfig.funnelId || undefined,
765
- funnelVersionId: runtimeConfig.funnelVersionId || undefined,
766
- planId: getPaywallPlanSelectionValue(input.plan),
767
- providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
768
- title: input.plan.title,
769
- description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
770
- amountCents: input.plan.amountCents,
771
- billingInterval: recurring.interval,
772
- billingIntervalCount: recurring.intervalCount,
773
- couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
774
- analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
775
- successUrl: input.successUrl,
776
- cancelUrl: input.cancelUrl,
777
- customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
778
- user_id: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
779
- environment: input.environment || undefined,
780
- }),
624
+ return funnelSdkService.createHostedCheckoutSession({
625
+ planId: getPaywallPlanSelectionValue(input.plan),
626
+ providerPlanId: ((_a = input.plan.providerPlanId) === null || _a === void 0 ? void 0 : _a.trim()) || undefined,
627
+ title: input.plan.title,
628
+ description: ((_b = input.plan.description) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
629
+ amountCents: input.plan.amountCents,
630
+ billingInterval: recurring.interval,
631
+ billingIntervalCount: recurring.intervalCount,
632
+ couponId: ((_c = input.couponId) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
633
+ analyticsMetadata: normalizeCheckoutAnalyticsMetadata(input.analyticsMetadata, input.plan),
634
+ successUrl: input.successUrl,
635
+ cancelUrl: input.cancelUrl,
636
+ customerEmail: ((_d = input.customerEmail) === null || _d === void 0 ? void 0 : _d.trim()) || undefined,
637
+ userId: ((_e = input.user_id) === null || _e === void 0 ? void 0 : _e.trim()) || undefined,
638
+ environment: input.environment,
639
+ runtimeConfig: input.runtimeConfig,
781
640
  });
782
- if (!response.ok) {
783
- const errorMessage = await parseErrorMessage(response, 'Unable to create checkout session');
784
- throw new Error(errorMessage);
785
- }
786
- return (await response.json());
787
641
  }
788
642
  export async function redirectToStripeCheckout(input) {
789
643
  var _a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/payments",
3
- "version": "0.1.46",
3
+ "version": "0.1.48",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",
@@ -27,8 +27,8 @@
27
27
  "test:run": "vitest run --passWithNoTests"
28
28
  },
29
29
  "dependencies": {
30
- "@funnelsgrove/analytics": "^0.1.15",
31
- "@funnelsgrove/runtime": "^0.1.18",
30
+ "@funnelsgrove/analytics": "^0.1.28",
31
+ "@funnelsgrove/runtime": "^0.1.46",
32
32
  "@stripe/react-stripe-js": "^5.6.0",
33
33
  "@stripe/stripe-js": "^8.7.0",
34
34
  "react": "19.2.3",