@funnelsgrove/runtime 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,6 +20,7 @@ documented in [`docs/product-specs/funnel-template-runtime.md`](../../docs/produ
20
20
  - funnel context, flow controller, and generic runtime UI primitives
21
21
  - funnel-scoped state/storage helpers
22
22
  - browser-safe API client helpers used by funnels
23
+ - reactive browser query-string access through `useBrowserLocationSearch`
23
24
  - subscription handoff and subscription management screens whose copy stays funnel-local
24
25
  - test-mode developer info surfaces for funnel preview tooling
25
26
 
@@ -54,6 +55,9 @@ documented in [`docs/product-specs/funnel-template-runtime.md`](../../docs/produ
54
55
  - Do not import `@funnelsgrove/payments` or `@funnelsgrove/analytics` here for checkout or transport orchestration.
55
56
  - Runtime UI must be generic and copy-injectable.
56
57
  - Browser-only values must resolve after mount when SSR hydration can be affected.
58
+ - Funnel code must not copy `useSyncExternalStore`/`popstate` query-string hooks. Use
59
+ `useBrowserLocationSearch`; the shared controller also notifies it after
60
+ `history.pushState` and `history.replaceState` navigation.
57
61
  - Keep env mapping centralized in `config/env.config.ts`.
58
62
 
59
63
  ## Build, Test, Publish
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ export * from './runtime/funnel-runtime.js';
18
18
  export type { FunnelNavigationOutcome, FunnelStepExitReason, } from './runtime/funnel-step-lifecycle.js';
19
19
  export * from './runtime/posthog-flags.js';
20
20
  export * from './runtime/use-funnel-flow-controller.js';
21
+ export * from './runtime/use-browser-location-search.js';
21
22
  export { useStepChoices } from './runtime/use-step-choices.js';
22
23
  export type { FunnelStepChoices } from './runtime/use-step-choices.js';
23
24
  export * from './runtime/preview-bridge.js';
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ export * from './runtime/funnel-step-metadata.validation.js';
20
20
  export * from './runtime/funnel-runtime.js';
21
21
  export * from './runtime/posthog-flags.js';
22
22
  export * from './runtime/use-funnel-flow-controller.js';
23
+ export * from './runtime/use-browser-location-search.js';
23
24
  export { useStepChoices } from './runtime/use-step-choices.js';
24
25
  export * from './runtime/preview-bridge.js';
25
26
  export * from './runtime/preview-definition-overrides.js';
@@ -1,8 +1,10 @@
1
1
  export declare const canUseDom: () => boolean;
2
+ export declare const FUNNEL_LOCATION_CHANGE_EVENT = "funnel:location-change";
2
3
  export declare const readWindowStorageValue: (storageKey: string) => string | null;
3
4
  export declare const writeWindowStorageValue: (storageKey: string, value: string) => void;
4
5
  export declare const removeWindowStorageValue: (storageKey: string) => void;
5
6
  export declare const dispatchWindowCustomEvent: <Detail>(eventType: string, detail: Detail) => void;
7
+ export declare const dispatchFunnelLocationChange: () => void;
6
8
  export declare const buildHostedStepLocation: (input: {
7
9
  currentHref: string;
8
10
  stepPath: string;
@@ -1,6 +1,7 @@
1
1
  export const canUseDom = () => {
2
2
  return typeof window !== 'undefined';
3
3
  };
4
+ export const FUNNEL_LOCATION_CHANGE_EVENT = 'funnel:location-change';
4
5
  export const readWindowStorageValue = (storageKey) => {
5
6
  if (!canUseDom()) {
6
7
  return null;
@@ -42,6 +43,14 @@ export const dispatchWindowCustomEvent = (eventType, detail) => {
42
43
  detail,
43
44
  }));
44
45
  };
46
+ export const dispatchFunnelLocationChange = () => {
47
+ if (!canUseDom()) {
48
+ return;
49
+ }
50
+ dispatchWindowCustomEvent(FUNNEL_LOCATION_CHANGE_EVENT, {
51
+ href: window.location.href,
52
+ });
53
+ };
45
54
  const getHostedFunnelBaseSegments = (pathname) => {
46
55
  const pathSegments = pathname.split('/').filter(Boolean);
47
56
  if (pathSegments[0] === 'published' && pathSegments[1] === 'f' && pathSegments[2]) {
@@ -0,0 +1,2 @@
1
+ export declare const getBrowserLocationSearch: () => string;
2
+ export declare const useBrowserLocationSearch: () => string;
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { useSyncExternalStore } from 'react';
3
+ import { FUNNEL_LOCATION_CHANGE_EVENT } from './browser-helpers.js';
4
+ const subscribeToBrowserLocationSearch = (onStoreChange) => {
5
+ if (typeof window === 'undefined') {
6
+ return () => undefined;
7
+ }
8
+ window.addEventListener('popstate', onStoreChange);
9
+ window.addEventListener(FUNNEL_LOCATION_CHANGE_EVENT, onStoreChange);
10
+ return () => {
11
+ window.removeEventListener('popstate', onStoreChange);
12
+ window.removeEventListener(FUNNEL_LOCATION_CHANGE_EVENT, onStoreChange);
13
+ };
14
+ };
15
+ export const getBrowserLocationSearch = () => {
16
+ return typeof window === 'undefined' ? '' : window.location.search;
17
+ };
18
+ export const useBrowserLocationSearch = () => {
19
+ return useSyncExternalStore(subscribeToBrowserLocationSearch, getBrowserLocationSearch, () => '');
20
+ };
@@ -4,7 +4,7 @@ import { writeStepChoice } from '../sdk/userAnswers.js';
4
4
  import { apiService } from '../services/api.service.js';
5
5
  import { logger } from '../services/logger.js';
6
6
  import { FUNNEL_ID, POSTHOG_API_HOST, POSTHOG_PROJECT_API_KEY, PROJECT_ID, } from '../services/runtime-api.config.js';
7
- import { buildHostedStepLocation, dispatchWindowCustomEvent, } from './browser-helpers.js';
7
+ import { buildHostedStepLocation, dispatchFunnelLocationChange, dispatchWindowCustomEvent, } from './browser-helpers.js';
8
8
  import { isPreviewStepLockRequested, resolveNextStepFromContext, shouldRunAutoAdvanceTimer, } from './funnel-flow.js';
9
9
  import { usePreviewBridge } from './preview-bridge.js';
10
10
  import { resolveExperimentAssignment, resolveForcedExperimentAssignment, } from './experiment-assignment.js';
@@ -422,6 +422,7 @@ export function useFunnelFlowController({ api = apiService, analytics, stepContr
422
422
  else {
423
423
  window.history.pushState({ stepId: safeStepId }, '', nextLocation);
424
424
  }
425
+ dispatchFunnelLocationChange();
425
426
  }
426
427
  setActiveStepId(safeStepId);
427
428
  }, [getPathForStep]);
@@ -212,10 +212,12 @@ export type FunnelSdkCreateOneTimePaymentIntentResponse = {
212
212
  };
213
213
  export type FunnelSdkChargeOneClickPaymentInput = {
214
214
  planId: string;
215
+ providerPlanId?: string | null;
215
216
  amountCents: number;
216
217
  analyticsMetadata?: Record<string, unknown> | null;
217
218
  checkoutSessionId?: string | null;
218
219
  currency?: string | null;
220
+ description?: string | null;
219
221
  environment?: FunnelSdkRuntimeMode;
220
222
  idempotencyKey?: string | null;
221
223
  runtimeConfig?: FunnelSdkRuntimeConfigOverrides;
@@ -329,8 +329,10 @@ class FunnelSdkService {
329
329
  runtimeConfig: input.runtimeConfig,
330
330
  body: {
331
331
  planId: input.planId,
332
+ providerPlanId: input.providerPlanId,
332
333
  amountCents: input.amountCents,
333
334
  currency: input.currency,
335
+ description: input.description,
334
336
  analyticsMetadata: input.analyticsMetadata,
335
337
  user_id: input.userId,
336
338
  stripe_customer_id: input.stripeCustomerId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@funnelsgrove/runtime",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/The-Solid-Grove/funnelsgrove.git",