@appfunnel-dev/sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -64,21 +64,28 @@ function useUser() {
64
64
  [variableStore]
65
65
  );
66
66
  const variables = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
67
- return react.useMemo(() => ({
68
- email: variables["user.email"] || "",
69
- name: variables["user.name"] || "",
70
- stripeCustomerId: variables["user.stripeCustomerId"] || "",
71
- paddleCustomerId: variables["user.paddleCustomerId"] || "",
72
- setEmail(email) {
73
- variableStore.set("user.email", email);
74
- tracker.identify(email);
75
- },
76
- setName(name) {
77
- variableStore.set("user.name", name);
78
- }
79
- }), [variables, variableStore, tracker]);
67
+ return react.useMemo(
68
+ () => ({
69
+ email: variables["user.email"] || "",
70
+ name: variables["user.name"] || "",
71
+ stripeCustomerId: variables["user.stripeCustomerId"] || "",
72
+ paddleCustomerId: variables["user.paddleCustomerId"] || "",
73
+ dateOfBirth: variables["user.dateOfBirth"] || "",
74
+ setEmail(email) {
75
+ variableStore.set("user.email", email);
76
+ tracker.identify(email);
77
+ },
78
+ setName(name) {
79
+ variableStore.set("user.name", name);
80
+ },
81
+ setDateOfBirth(dateOfBirth) {
82
+ variableStore.set("user.dateOfBirth", dateOfBirth);
83
+ }
84
+ }),
85
+ [variables, variableStore, tracker]
86
+ );
80
87
  }
81
- function useUserVariable(field) {
88
+ function useUserProperty(field) {
82
89
  const { variableStore } = useFunnelContext();
83
90
  const key = `user.${field}`;
84
91
  const subscribe = react.useCallback(
@@ -96,6 +103,45 @@ function useUserVariable(field) {
96
103
  );
97
104
  return [value, setValue];
98
105
  }
106
+ function useResponse(key) {
107
+ const { variableStore } = useFunnelContext();
108
+ const prefixedKey = `answers.${key}`;
109
+ const subscribe = react.useCallback(
110
+ (cb) => variableStore.subscribe(cb),
111
+ [variableStore]
112
+ );
113
+ const getSnapshot = react.useCallback(
114
+ () => variableStore.get(prefixedKey),
115
+ [variableStore, prefixedKey]
116
+ );
117
+ const value = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
118
+ const setValue = react.useCallback(
119
+ (v) => variableStore.set(prefixedKey, v),
120
+ [variableStore, prefixedKey]
121
+ );
122
+ return [value, setValue];
123
+ }
124
+ function useResponses() {
125
+ const { variableStore } = useFunnelContext();
126
+ const subscribe = react.useCallback(
127
+ (cb) => variableStore.subscribe(cb),
128
+ [variableStore]
129
+ );
130
+ const getSnapshot = react.useCallback(
131
+ () => variableStore.getState(),
132
+ [variableStore]
133
+ );
134
+ const variables = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
135
+ return react.useMemo(() => {
136
+ const result = {};
137
+ for (const [key, value] of Object.entries(variables)) {
138
+ if (key.startsWith("answers.")) {
139
+ result[key.slice(8)] = value;
140
+ }
141
+ }
142
+ return result;
143
+ }, [variables]);
144
+ }
99
145
  function useQueryParams() {
100
146
  const { variableStore } = useFunnelContext();
101
147
  const subscribe = react.useCallback(
@@ -117,6 +163,37 @@ function useQueryParams() {
117
163
  return params;
118
164
  }, [variables]);
119
165
  }
166
+ function useQueryParam(key) {
167
+ const { variableStore } = useFunnelContext();
168
+ const prefixedKey = `query.${key}`;
169
+ const subscribe = react.useCallback(
170
+ (cb) => variableStore.subscribe(cb),
171
+ [variableStore]
172
+ );
173
+ const getSnapshot = react.useCallback(
174
+ () => variableStore.get(prefixedKey) || "",
175
+ [variableStore, prefixedKey]
176
+ );
177
+ return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
178
+ }
179
+ function useData(key) {
180
+ const { variableStore } = useFunnelContext();
181
+ const prefixedKey = `data.${key}`;
182
+ const subscribe = react.useCallback(
183
+ (cb) => variableStore.subscribe(cb),
184
+ [variableStore]
185
+ );
186
+ const getSnapshot = react.useCallback(
187
+ () => variableStore.get(prefixedKey),
188
+ [variableStore, prefixedKey]
189
+ );
190
+ const value = react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
191
+ const setValue = react.useCallback(
192
+ (v) => variableStore.set(prefixedKey, v),
193
+ [variableStore, prefixedKey]
194
+ );
195
+ return [value, setValue];
196
+ }
120
197
  function useLocale() {
121
198
  return react.useMemo(() => {
122
199
  if (typeof navigator === "undefined") {
@@ -332,6 +409,7 @@ function useFunnel() {
332
409
  sessionId: tracker.getSessionId(),
333
410
  variables: useVariables(),
334
411
  user: useUser(),
412
+ responses: useResponses(),
335
413
  queryParams: useQueryParams(),
336
414
  navigation: useNavigation(),
337
415
  products: useProducts(),
@@ -644,16 +722,20 @@ exports.PaymentForm = PaymentForm;
644
722
  exports.defineConfig = defineConfig;
645
723
  exports.definePage = definePage;
646
724
  exports.registerIntegration = registerIntegration;
725
+ exports.useData = useData;
647
726
  exports.useFunnel = useFunnel;
648
727
  exports.useLocale = useLocale;
649
728
  exports.useNavigation = useNavigation;
650
729
  exports.usePayment = usePayment;
651
730
  exports.useProducts = useProducts;
731
+ exports.useQueryParam = useQueryParam;
652
732
  exports.useQueryParams = useQueryParams;
733
+ exports.useResponse = useResponse;
734
+ exports.useResponses = useResponses;
653
735
  exports.useTracking = useTracking;
654
736
  exports.useTranslation = useTranslation;
655
737
  exports.useUser = useUser;
656
- exports.useUserVariable = useUserVariable;
738
+ exports.useUserProperty = useUserProperty;
657
739
  exports.useVariable = useVariable;
658
740
  exports.useVariables = useVariables;
659
741
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/runtime/integrations.ts","../src/components/FunnelProvider.tsx","../src/hooks/useVariable.ts","../src/hooks/useVariables.ts","../src/hooks/useUser.ts","../src/hooks/useQueryParams.ts","../src/hooks/useLocale.ts","../src/hooks/useTranslation.ts","../src/hooks/useNavigation.ts","../src/hooks/useProducts.ts","../src/hooks/useTracking.ts","../src/hooks/usePayment.ts","../src/hooks/useFunnel.ts","../src/components/PaymentForm.tsx","../src/components/PaddleCheckout.tsx"],"names":["createContext","useContext","useCallback","useSyncExternalStore","useMemo","useStripe","useElements","useState","response","result","useEffect","jsx","PaymentElement","useRef","loadStripe","Elements"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AppFunnelConfig, PageDefinition } from './types'\n\n/**\n * Type helper for appfunnel.config.ts.\n * Returns the config object unchanged — exists purely for TypeScript autocomplete.\n */\nexport function defineConfig(config: AppFunnelConfig): AppFunnelConfig {\n return config\n}\n\n/**\n * Define page metadata co-located with the page component.\n * Export this from your page file alongside the default React component.\n *\n * @example\n * ```tsx\n * // pages/quiz.tsx\n * import { definePage, useVariable, useNavigation } from '@appfunnel-dev/sdk'\n *\n * export const page = definePage({\n * name: 'Quiz',\n * type: 'default',\n * routes: [\n * { to: 'checkout', when: { variable: 'plan', equals: 'premium' } },\n * { to: 'success' }, // fallback\n * ],\n * })\n *\n * export default function Quiz() {\n * // ...\n * }\n * ```\n *\n * The CLI build step collects all `page` exports and assembles them into\n * the full config (pages map + routes map + computed route manifest for analytics).\n */\nexport function definePage(definition: PageDefinition): PageDefinition {\n return definition\n}\n","/**\n * Integration runtime — sets up window.appfunnel event bus and initializes\n * third-party integrations (Meta Pixel, GTM, Clarity, etc.).\n *\n * The integration loaders from the admin codebase subscribe to events via\n * window.appfunnel.on(). The FunnelTracker emits events via _emitEvent().\n * This module bridges the two by setting up the pub/sub layer.\n */\n\nimport type { VariableValue } from '../types'\nimport type { VariableStore } from './variableStore'\nimport type { Router } from './router'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Integration config map: integrationId -> config object */\nexport type IntegrationConfigs = Record<string, Record<string, unknown>>\n\ntype EventCallback = (data: unknown) => void\n\ninterface Subscription {\n callback: EventCallback\n scope: 'global' | 'page'\n}\n\n// ============================================================================\n// AppFunnel Runtime (window.appfunnel event bus)\n// ============================================================================\n\nexport class AppFunnelEventBus {\n private subscriptions = new Map<string, Subscription[]>()\n private store: VariableStore\n private router: Router\n private selectProduct: (productId: string) => void\n\n constructor(\n store: VariableStore,\n router: Router,\n selectProduct: (productId: string) => void,\n ) {\n this.store = store\n this.router = router\n this.selectProduct = selectProduct\n }\n\n /** Attach the event bus to window.appfunnel */\n attach(): void {\n if (typeof window === 'undefined') return\n\n const self = this\n\n ;(window as unknown as Record<string, unknown>).appfunnel = {\n // Event subscriptions\n on(eventType: string, callback: EventCallback): () => void {\n return self.on(eventType, callback)\n },\n off(eventType: string, callback: EventCallback): void {\n self.off(eventType, callback)\n },\n\n // Internal — called by FunnelTracker.emitToRuntime()\n _emitEvent(eventType: string, data?: unknown): void {\n self.emit(eventType, data)\n },\n\n // Getters for integration loaders that need them\n getVariable(variableId: string): VariableValue {\n return self.store.get(variableId)\n },\n getVariables(): Record<string, VariableValue> {\n return { ...self.store.getState() }\n },\n getCurrentPageId(): string | null {\n return self.router.getCurrentPage()?.key ?? null\n },\n getCustomerId(): string | null {\n return (self.store.get('user.stripeCustomerId') as string) || null\n },\n isPaymentAuthorized(): boolean {\n return !!(self.store.get('user.stripeCustomerId') as string)\n },\n\n // Methods\n setVariable(variableId: string, value: VariableValue): void {\n self.store.set(variableId, value)\n },\n selectProduct(productId: string): void {\n self.selectProduct(productId)\n },\n goToNextPage(): void {\n self.router.goToNextPage(self.store.getState())\n },\n goBack(): void {\n self.router.goBack()\n },\n openUrl(url: string): void {\n if (url) window.open(url, '_blank', 'noopener,noreferrer')\n },\n callEvent(eventName: string, data?: Record<string, unknown>): void {\n self.emit(eventName, data)\n },\n\n // Debug\n debug: false,\n setDebug(_enabled: boolean): void { /* noop in SDK */ },\n }\n }\n\n /** Emit an event to all subscribers */\n emit(eventType: string, data?: unknown): void {\n const subs = this.subscriptions.get(eventType)\n if (!subs || subs.length === 0) return\n\n for (const sub of subs) {\n try {\n sub.callback(data)\n } catch (error) {\n console.error(`[AppFunnel] Error in event handler for \"${eventType}\":`, error)\n }\n }\n }\n\n /** Clean up page-scoped subscriptions (called on page change) */\n onPageChange(): void {\n for (const [eventType, subs] of this.subscriptions.entries()) {\n this.subscriptions.set(eventType, subs.filter((s) => s.scope === 'global'))\n }\n }\n\n /** Destroy and detach from window */\n destroy(): void {\n this.subscriptions.clear()\n if (typeof window !== 'undefined') {\n delete (window as unknown as Record<string, unknown>).appfunnel\n }\n }\n\n private on(eventType: string, callback: EventCallback): () => void {\n if (!this.subscriptions.has(eventType)) {\n this.subscriptions.set(eventType, [])\n }\n const sub: Subscription = { callback, scope: 'global' }\n this.subscriptions.get(eventType)!.push(sub)\n return () => this.off(eventType, callback)\n }\n\n private off(eventType: string, callback: EventCallback): void {\n const subs = this.subscriptions.get(eventType)\n if (!subs) return\n const index = subs.findIndex((s) => s.callback === callback)\n if (index > -1) subs.splice(index, 1)\n }\n}\n\n// ============================================================================\n// Integration Loader Registry\n// ============================================================================\n\ntype IntegrationLoader = (config: Record<string, unknown>) => void\n\nconst loaders: Record<string, IntegrationLoader> = {}\n\n/**\n * Register a custom integration loader.\n * Called by the CLI build or user code to add integrations.\n */\nexport function registerIntegration(id: string, loader: IntegrationLoader): void {\n loaders[id] = loader\n}\n\n/**\n * Initialize all integrations from config.\n * Must be called after AppFunnelEventBus.attach() so window.appfunnel exists.\n */\nexport function initializeIntegrations(integrations: IntegrationConfigs): void {\n if (typeof window === 'undefined') return\n\n ;(window as unknown as Record<string, unknown>).__INTEGRATIONS__ = integrations\n\n for (const [integrationId, config] of Object.entries(integrations)) {\n const loader = loaders[integrationId]\n if (loader) {\n try {\n loader(config)\n } catch (err) {\n console.error(`[AppFunnel] Error loading integration ${integrationId}:`, err)\n }\n }\n }\n}\n","import { createContext, useContext, useEffect, useRef, useMemo, useCallback } from 'react'\nimport type {\n AppFunnelConfig,\n VariableValue,\n RuntimeProduct,\n EnrichedPriceData,\n} from '../types'\nimport { VariableStore, createVariableStore } from '../runtime/variableStore'\nimport { Router } from '../runtime/router'\nimport { FunnelTracker } from '../runtime/tracker'\nimport { buildRuntimeProducts } from '../runtime/products'\nimport { computeSystemVariables, startSystemVariableUpdater } from '../runtime/systemVariables'\nimport { AppFunnelEventBus, initializeIntegrations } from '../runtime/integrations'\nimport { I18n, type TranslationMap } from '../runtime/i18n'\n\n// ============================================================================\n// Context\n// ============================================================================\n\nexport interface FunnelContextValue {\n config: AppFunnelConfig\n variableStore: VariableStore\n router: Router\n tracker: FunnelTracker\n i18n: I18n\n products: RuntimeProduct[]\n selectedProductId: string | null\n selectProduct: (productId: string) => void\n funnelId: string\n campaignId: string\n sessionId: string | null\n apiBaseUrl: string\n}\n\nconst FunnelContext = createContext<FunnelContextValue | null>(null)\n\nexport function useFunnelContext(): FunnelContextValue {\n const ctx = useContext(FunnelContext)\n if (!ctx) {\n throw new Error('useFunnelContext must be used within a <FunnelProvider>')\n }\n return ctx\n}\n\n// ============================================================================\n// Provider Props\n// ============================================================================\n\nexport interface FunnelProviderProps {\n config: AppFunnelConfig\n children: React.ReactNode\n /** Pre-fetched session data (from API) */\n sessionData?: {\n sessionId?: string\n campaignId: string\n funnelId: string\n variables?: Record<string, VariableValue>\n customerId?: string\n experimentId?: string | null\n }\n /** Pre-fetched enriched price data map: storePriceId → price data */\n priceData?: Map<string, EnrichedPriceData>\n /** API base URL override */\n apiBaseUrl?: string\n /** Campaign slug for session cookies */\n campaignSlug?: string\n /** Override the initial page (e.g. from URL slug on reload/deep link) */\n initialPage?: string\n /** Translations map: { \"en\": { \"key\": \"value\" }, \"de\": { \"key\": \"wert\" } } */\n translations?: TranslationMap\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport function FunnelProvider({\n config,\n children,\n sessionData,\n priceData,\n apiBaseUrl = '',\n campaignSlug,\n initialPage,\n translations,\n}: FunnelProviderProps) {\n const campaignId = sessionData?.campaignId || config.projectId\n const funnelId = sessionData?.funnelId || config.projectId\n\n // ── Initialize runtime objects (once) ─────────────\n const storeRef = useRef<VariableStore | null>(null)\n const routerRef = useRef<Router | null>(null)\n const trackerRef = useRef<FunnelTracker | null>(null)\n const eventBusRef = useRef<AppFunnelEventBus | null>(null)\n const i18nRef = useRef<I18n | null>(null)\n\n if (!storeRef.current) {\n storeRef.current = createVariableStore(config.variables, sessionData?.variables)\n }\n if (!routerRef.current) {\n routerRef.current = new Router(config, initialPage)\n }\n if (!trackerRef.current) {\n trackerRef.current = new FunnelTracker(apiBaseUrl)\n }\n if (!i18nRef.current) {\n const i18n = new I18n(config.defaultLocale || 'en')\n if (translations) i18n.load(translations)\n // Auto-detect locale from browser if available\n if (typeof navigator !== 'undefined') {\n const browserLang = navigator.language?.split('-')[0]\n if (browserLang && translations?.[browserLang]) {\n i18n.setLocale(browserLang)\n }\n }\n i18nRef.current = i18n\n }\n\n const store = storeRef.current\n const router = routerRef.current\n const tracker = trackerRef.current\n const i18n = i18nRef.current\n\n // ── Build products ────────────────────────────────\n const products = useMemo(() => {\n if (!config.products?.items || !priceData) return []\n return buildRuntimeProducts(config.products.items, priceData)\n }, [config.products, priceData])\n\n // ── Selected product ──────────────────────────────\n const defaultProductId = config.products?.defaultId || products[0]?.id || null\n const selectedProductIdRef = useRef<string | null>(defaultProductId)\n\n const selectProduct = useCallback((productId: string) => {\n selectedProductIdRef.current = productId\n store.set('products.selectedProductId', productId)\n }, [store])\n\n // ── Event bus + integrations ──────────────────────\n useEffect(() => {\n const eventBus = new AppFunnelEventBus(store, router, selectProduct)\n eventBus.attach()\n eventBusRef.current = eventBus\n\n // Initialize third-party integrations (Meta Pixel, GTM, Clarity, etc.)\n if (config.integrations && Object.keys(config.integrations).length > 0) {\n initializeIntegrations(config.integrations)\n }\n\n return () => {\n eventBus.destroy()\n eventBusRef.current = null\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Initialize tracker ────────────────────────────\n useEffect(() => {\n tracker.init(campaignId, funnelId, campaignSlug, sessionData?.experimentId)\n\n if (sessionData?.sessionId) {\n tracker.setSessionId(sessionData.sessionId)\n }\n\n // Fire initial events\n const currentPage = router.getCurrentPage()\n tracker.track('funnel.start')\n if (currentPage) {\n tracker.track('page.view', {\n pageId: currentPage.key,\n pageKey: currentPage.key,\n pageName: currentPage.name,\n isInitial: true,\n })\n tracker.startPageTracking(currentPage.key)\n }\n\n return () => {\n tracker.stopPageTracking()\n tracker.flushVariables()\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── System variables ──────────────────────────────\n const sessionStartTime = useRef(Date.now())\n const pageStartTime = useRef(Date.now())\n\n useEffect(() => {\n const sysVars = computeSystemVariables({\n currentPageKey: router.getCurrentPage()?.key || '',\n pageHistory: router.getPageHistory(),\n pageStartTime: pageStartTime.current,\n sessionStartTime: sessionStartTime.current,\n totalPages: Object.keys(config.pages ?? {}).length,\n funnelId,\n campaignId,\n })\n store.setMany(sysVars)\n\n if (defaultProductId) {\n store.set('products.selectedProductId', defaultProductId)\n }\n\n const stopUpdater = startSystemVariableUpdater(store, () => ({\n currentPageKey: router.getCurrentPage()?.key || '',\n pageHistory: router.getPageHistory(),\n pageStartTime: pageStartTime.current,\n sessionStartTime: sessionStartTime.current,\n totalPages: Object.keys(config.pages ?? {}).length,\n funnelId,\n campaignId,\n }))\n\n return stopUpdater\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Sync variables to tracker for persistence ─────\n useEffect(() => {\n return store.subscribe(() => {\n tracker.setCurrentVariables(store.getState() as Record<string, unknown>)\n })\n }, [store, tracker])\n\n // ── Context value ─────────────────────────────────\n const contextValue = useMemo<FunnelContextValue>(() => ({\n config,\n variableStore: store,\n router,\n tracker,\n i18n,\n products,\n selectedProductId: selectedProductIdRef.current,\n selectProduct,\n funnelId,\n campaignId,\n sessionId: tracker.getSessionId(),\n apiBaseUrl,\n }), [config, store, router, tracker, i18n, products, selectProduct, funnelId, campaignId, apiBaseUrl])\n\n return (\n <FunnelContext.Provider value={contextValue}>\n {children}\n </FunnelContext.Provider>\n )\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read/write a single variable.\n *\n * ```tsx\n * const [email, setEmail] = useVariable<string>('email')\n * const [count, setCount] = useVariable<number>('count')\n * const [agreed, setAgreed] = useVariable<boolean>('agreed')\n * const [tags, setTags] = useVariable<string[]>('tags')\n * ```\n */\nexport function useVariable<T extends VariableValue>(\n id: string,\n): [T, (value: T) => void] {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (callback: () => void) => variableStore.subscribe(callback),\n [variableStore],\n )\n\n const getSnapshot = useCallback(\n () => variableStore.get(id) as T,\n [variableStore, id],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: T) => variableStore.set(id, v),\n [variableStore, id],\n )\n\n return [value, setValue]\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read all variables (including system variables). Read-only.\n * Use useVariable() to write individual variables.\n */\nexport function useVariables(): Record<string, VariableValue> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (callback: () => void) => variableStore.subscribe(callback),\n [variableStore],\n )\n\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { UserState } from '../types'\n\n/**\n * Read built-in user state (email, name, customerId).\n *\n * For reading/writing arbitrary user fields, use `useUserVariable('fieldName')`.\n */\nexport function useUser(): UserState {\n const { variableStore, tracker } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => ({\n email: (variables['user.email'] as string) || '',\n name: (variables['user.name'] as string) || '',\n stripeCustomerId: (variables['user.stripeCustomerId'] as string) || '',\n paddleCustomerId: (variables['user.paddleCustomerId'] as string) || '',\n\n setEmail(email: string) {\n variableStore.set('user.email', email)\n tracker.identify(email)\n },\n setName(name: string) {\n variableStore.set('user.name', name)\n },\n }), [variables, variableStore, tracker])\n}\n\n/**\n * Read/write a user variable by field name.\n * Auto-prefixes with `user.` — no need to define in config.\n *\n * ```tsx\n * const [dob, setDob] = useUserVariable('dateOfBirth')\n * const [gender, setGender] = useUserVariable('gender')\n * ```\n */\nexport function useUserVariable(field: string): [string, (value: string) => void] {\n const { variableStore } = useFunnelContext()\n const key = `user.${field}`\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => (variableStore.get(key) as string) || '',\n [variableStore, key],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: string) => variableStore.set(key, v),\n [variableStore, key],\n )\n\n return [value, setValue]\n}\n","import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\n\n/**\n * Read URL query parameters.\n *\n * `query.*` variables are auto-populated from `window.location.search`.\n * e.g. `?utm_source=google&ref=abc` → `{ utm_source: 'google', ref: 'abc' }`.\n *\n * These are read-only from the developer's perspective — they come from the URL.\n * Under the hood, they live in the variable store as `query.utm_source`, etc.\n *\n * Note: The CLI build still emits all `query.*` variables to the published config\n * so they can be queried in the analytics database.\n */\nexport function useQueryParams(): Record<string, string> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const params: Record<string, string> = {}\n for (const [key, value] of Object.entries(variables)) {\n if (key.startsWith('query.') && typeof value === 'string') {\n params[key.slice(6)] = value\n }\n }\n return params\n }, [variables])\n}\n","import { useMemo } from 'react'\nimport type { LocaleState } from '../types'\n\n/**\n * Get the user's locale from the browser.\n *\n * Provides language, region, and currency info derived from the browser.\n * Combine with i18n libraries (react-i18next, next-intl, etc.) for translations.\n *\n * ```tsx\n * const { language, region, currency } = useLocale()\n * // language: 'en', region: 'US', currency: 'USD'\n * ```\n */\nexport function useLocale(): LocaleState {\n return useMemo(() => {\n if (typeof navigator === 'undefined') {\n return {\n locale: 'en-US',\n language: 'en',\n region: 'US',\n languages: ['en-US'],\n timeZone: 'UTC',\n is24Hour: false,\n }\n }\n\n const locale = navigator.language || 'en-US'\n const [language, region] = locale.split('-')\n const languages = [...(navigator.languages || [locale])]\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'\n const is24Hour = detect24Hour(locale)\n\n return {\n locale,\n language: language || 'en',\n region: region?.toUpperCase() || 'US',\n languages,\n timeZone,\n is24Hour,\n }\n }, [])\n}\n\n/** Detect if locale likely uses 24h clock */\nfunction detect24Hour(locale: string): boolean {\n try {\n const formatted = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).format(new Date())\n return !formatted.match(/am|pm/i)\n } catch {\n return false\n }\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { TranslationState } from '../types'\n\n/**\n * Access translations for the current locale.\n *\n * ```tsx\n * const { t, locale, setLocale } = useTranslation()\n *\n * return (\n * <div>\n * <h1>{t('welcome', { name: 'John' })}</h1>\n * <button onClick={() => setLocale('de')}>Deutsch</button>\n * </div>\n * )\n * ```\n */\nexport function useTranslation(): TranslationState {\n const { i18n } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => i18n.subscribe(cb),\n [i18n],\n )\n const getSnapshot = useCallback(\n () => i18n.getLocale(),\n [i18n],\n )\n\n const locale = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const t = useCallback(\n (key: string, params?: Record<string, string | number>) => i18n.t(key, params),\n [i18n, locale], // eslint-disable-line react-hooks/exhaustive-deps\n )\n\n const setLocale = useCallback(\n (l: string) => i18n.setLocale(l),\n [i18n],\n )\n\n const availableLocales = i18n.getAvailableLocales()\n\n return { t, locale, setLocale, availableLocales }\n}\n","import { useCallback, useSyncExternalStore } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { NavigationState } from '../types'\n\n/**\n * Navigation hook — evaluates routes, navigates between pages, tracks progress.\n */\nexport function useNavigation(): NavigationState {\n const { router, variableStore, tracker } = useFunnelContext()\n\n // Re-render when variables change (routes depend on variable state)\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const goToNextPage = useCallback(() => {\n const previousPage = router.getCurrentPage()\n if (previousPage) {\n tracker.stopPageTracking()\n }\n\n const nextKey = router.goToNextPage(variables)\n if (nextKey) {\n const nextPage = router.getCurrentPage()\n if (nextPage) {\n tracker.track('page.view', {\n pageId: nextPage.key,\n pageKey: nextPage.key,\n pageName: nextPage.name,\n })\n tracker.startPageTracking(nextPage.key)\n }\n // Update system variables\n variableStore.setMany({\n 'page.currentId': nextKey,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n 'page.timeOnCurrent': 0,\n })\n }\n }, [router, variables, tracker, variableStore])\n\n const goBack = useCallback(() => {\n tracker.stopPageTracking()\n const prevKey = router.goBack()\n if (prevKey) {\n const page = router.getCurrentPage()\n if (page) {\n tracker.track('page.view', {\n pageId: page.key,\n pageKey: page.key,\n pageName: page.name,\n })\n tracker.startPageTracking(page.key)\n }\n variableStore.setMany({\n 'page.currentId': prevKey,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n 'page.timeOnCurrent': 0,\n })\n }\n }, [router, tracker, variableStore])\n\n const goToPage = useCallback((pageKey: string) => {\n tracker.stopPageTracking()\n const key = router.goToPage(pageKey)\n if (key) {\n const page = router.getCurrentPage()\n if (page) {\n tracker.track('page.view', {\n pageId: page.key,\n pageKey: page.key,\n pageName: page.name,\n })\n tracker.startPageTracking(page.key)\n }\n variableStore.setMany({\n 'page.currentId': key,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n 'page.timeOnCurrent': 0,\n })\n }\n }, [router, tracker, variableStore])\n\n return {\n goToNextPage,\n goBack,\n goToPage,\n currentPage: router.getCurrentPage(),\n pageHistory: router.getPageHistory(),\n progress: router.getProgress(),\n }\n}\n","import { useCallback, useSyncExternalStore } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { ProductsState } from '../types'\n\n/**\n * Products hook — access product list, selected product, and selection handler.\n */\nexport function useProducts(): ProductsState {\n const { products, variableStore, selectProduct: ctxSelect } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.get('products.selectedProductId') as string | null,\n [variableStore],\n )\n\n const selectedId = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const selected = products.find((p) => p.id === selectedId) || null\n\n const select = useCallback((productId: string) => {\n ctxSelect(productId)\n }, [ctxSelect])\n\n return { products, selected, select }\n}\n","import { useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { TrackingState } from '../types'\n\n/**\n * Tracking hook — fire events and identify users.\n */\nexport function useTracking(): TrackingState {\n const { tracker } = useFunnelContext()\n\n const track = useCallback(\n (eventName: string, data?: Record<string, unknown>) => {\n tracker.track(eventName, data)\n },\n [tracker],\n )\n\n const identify = useCallback(\n (email: string) => {\n tracker.identify(email)\n },\n [tracker],\n )\n\n return { track, identify }\n}\n","import { useCallback, useSyncExternalStore, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { PaymentState } from '../types'\n\n/**\n * Payment hook — reads payment-related system variables.\n */\nexport function usePayment(): PaymentState {\n const { variableStore, tracker } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const last4 = variables['card.last4'] as string || ''\n const brand = variables['card.brand'] as string || ''\n const expMonth = variables['card.expMonth'] as number || 0\n const expYear = variables['card.expYear'] as number || 0\n\n return {\n customerId: tracker.getCustomerId(),\n isAuthorized: !!last4,\n loading: !!variables['payment.loading'],\n error: (variables['payment.error'] as string) || null,\n cardDetails: last4\n ? { last4, brand, expMonth, expYear }\n : null,\n }\n }, [variables, tracker])\n}\n","import { useFunnelContext } from '../components/FunnelProvider'\nimport { useVariables } from './useVariables'\nimport { useUser } from './useUser'\nimport { useQueryParams } from './useQueryParams'\nimport { useNavigation } from './useNavigation'\nimport { useProducts } from './useProducts'\nimport { useTracking } from './useTracking'\nimport { usePayment } from './usePayment'\nimport type { FunnelState } from '../types'\n\n/**\n * Convenience hook that combines all SDK hooks.\n * Useful for simple funnels where you don't want multiple hook imports.\n */\nexport function useFunnel(): FunnelState {\n const { funnelId, campaignId, tracker } = useFunnelContext()\n\n return {\n funnelId,\n campaignId,\n sessionId: tracker.getSessionId(),\n variables: useVariables(),\n user: useUser(),\n queryParams: useQueryParams(),\n navigation: useNavigation(),\n products: useProducts(),\n tracking: useTracking(),\n payment: usePayment(),\n }\n}\n","import { useEffect, useState, useRef, useCallback, useMemo } from 'react'\nimport { loadStripe, type Stripe, type Appearance } from '@stripe/stripe-js'\nimport {\n Elements,\n PaymentElement,\n useStripe,\n useElements,\n} from '@stripe/react-stripe-js'\nimport { useFunnelContext } from './FunnelProvider'\nimport { useVariable } from '../hooks/useVariable'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PaymentFormProps {\n /** Product ID override (default: currently selected product) */\n productId?: string\n /** \"checkout\" for full payment, \"validate-only\" to just collect card */\n mode?: 'checkout' | 'validate-only'\n /** Called on successful payment */\n onSuccess?: () => void\n /** Called on payment error */\n onError?: (error: string) => void\n /** Allow Stripe promotion codes */\n allowPromotionCodes?: boolean\n /** Additional CSS class */\n className?: string\n /** Stripe Appearance override */\n appearance?: Appearance\n}\n\n// ============================================================================\n// Inner Form (uses Stripe hooks)\n// ============================================================================\n\nfunction InnerPaymentForm({\n paymentMode,\n validateOnly,\n onSuccess,\n onError,\n}: {\n paymentMode: 'setup' | 'payment'\n validateOnly: boolean\n onSuccess?: () => void\n onError?: (error: string) => void\n}) {\n const stripe = useStripe()\n const elements = useElements()\n const [error, setError] = useState<string | null>(null)\n const { variableStore, campaignId, tracker, apiBaseUrl, products } = useFunnelContext()\n\n const handleSubmit = useCallback(async () => {\n if (!stripe || !elements) {\n const msg = 'Stripe not loaded'\n setError(msg)\n onError?.(msg)\n return\n }\n\n setError(null)\n variableStore.set('payment.loading', true)\n\n try {\n const confirmFn = paymentMode === 'setup' ? stripe.confirmSetup : stripe.confirmPayment\n const confirmResult = await confirmFn({\n elements,\n redirect: 'if_required',\n confirmParams: { return_url: window.location.href },\n })\n\n if (confirmResult.error) {\n const msg = confirmResult.error.message || 'Payment failed'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n tracker.track('checkout.payment_added')\n\n if (validateOnly) {\n const piId = 'paymentIntent' in confirmResult\n ? (confirmResult as Record<string, unknown>).paymentIntent as { id?: string } | undefined\n : undefined\n\n if (!piId?.id) {\n const msg = 'PaymentIntent not found after confirmation'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n const response = await fetch(\n `${apiBaseUrl}/campaign/${campaignId}/stripe/validate-card`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n campaignId,\n sessionId: tracker.getSessionId(),\n paymentIntentId: piId.id,\n }),\n },\n )\n\n const result = await response.json()\n\n if (!result.success) {\n const msg = result.error || 'Card validation failed'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n variableStore.setMany({\n 'card.last4': result.card.last4,\n 'card.brand': result.card.brand,\n 'card.expMonth': result.card.expMonth,\n 'card.expYear': result.card.expYear,\n 'card.funding': result.card.funding,\n 'payment.error': '',\n })\n\n onSuccess?.()\n return\n }\n\n // ── Normal purchase path ──\n const paymentIntentId = 'paymentIntent' in confirmResult\n ? ((confirmResult as Record<string, unknown>).paymentIntent as { id?: string })?.id\n : undefined\n\n const selectedId = variableStore.get('products.selectedProductId') as string\n const product = products.find((p) => p.id === selectedId)\n\n if (!product?.stripePriceId) {\n const msg = 'No product selected or missing Stripe price'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n const variables = variableStore.getState()\n await tracker.updateUserData(variables as Record<string, unknown>)\n\n const response = await fetch(\n `${apiBaseUrl}/campaign/${campaignId}/stripe/purchase`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n campaignId,\n sessionId: tracker.getSessionId(),\n stripePriceId: product.stripePriceId,\n trialPeriodDays: product.hasTrial ? product.trialDays : undefined,\n onSessionPiId: paymentMode === 'payment' ? paymentIntentId : undefined,\n }),\n },\n )\n\n const result = await response.json()\n\n if (result.success) {\n variableStore.set('payment.error', '')\n if (result.eventId || result.eventIds?.firstPeriod) {\n tracker.track('purchase.complete', {\n amount: product.rawPrice ? product.rawPrice / 100 : 0,\n currency: product.currencyCode || 'USD',\n })\n }\n onSuccess?.()\n } else {\n const msg = result.error || 'Failed to process payment'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : 'An error occurred'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n } finally {\n variableStore.set('payment.loading', false)\n }\n }, [stripe, elements, paymentMode, validateOnly, variableStore, campaignId, tracker, apiBaseUrl, products, onSuccess, onError])\n\n // Register submit handler globally for external triggering\n useEffect(() => {\n if (typeof window !== 'undefined') {\n ;(window as unknown as Record<string, unknown>).__paymentElementSubmit = handleSubmit\n }\n return () => {\n if (typeof window !== 'undefined') {\n delete (window as unknown as Record<string, unknown>).__paymentElementSubmit\n }\n }\n }, [handleSubmit])\n\n return (\n <div>\n <PaymentElement options={{ layout: 'tabs' }} />\n {error && (\n <div style={{ color: '#ef4444', fontSize: '14px', marginTop: '12px' }}>\n {error}\n </div>\n )}\n </div>\n )\n}\n\n// ============================================================================\n// PaymentForm (public component)\n// ============================================================================\n\nexport function PaymentForm({\n productId,\n mode = 'checkout',\n onSuccess,\n onError,\n className,\n appearance,\n}: PaymentFormProps) {\n const { campaignId, tracker, variableStore, apiBaseUrl, products } = useFunnelContext()\n const [email] = useVariable<string>('user.email')\n\n const validateOnly = mode === 'validate-only'\n\n // Resolve the product\n const product = useMemo(() => {\n if (productId) return products.find((p) => p.id === productId) || null\n const selectedId = variableStore.get('products.selectedProductId') as string\n return products.find((p) => p.id === selectedId) || null\n }, [productId, products, variableStore])\n\n // Derive payment mode from product\n const paymentMode = useMemo((): 'setup' | 'payment' => {\n if (validateOnly) return 'payment'\n if (product?.hasTrial && !product.paidTrial) return 'setup'\n return 'payment'\n }, [product, validateOnly])\n\n const [stripePromise, setStripePromise] = useState<Promise<Stripe | null> | null>(null)\n const [clientSecret, setClientSecret] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const hasInitialized = useRef(false)\n\n // Create intent when email is available\n useEffect(() => {\n if (!email || !campaignId || hasInitialized.current) return\n if (!product?.storePriceId) return\n\n hasInitialized.current = true\n setIsLoading(true)\n variableStore.set('payment.loading', true)\n\n const createIntent = async () => {\n try {\n const endpoint = paymentMode === 'setup'\n ? `/campaign/${campaignId}/stripe/setup-intent`\n : `/campaign/${campaignId}/stripe/payment-intent`\n\n const body: Record<string, unknown> = {\n campaignId,\n sessionId: tracker.getSessionId(),\n customerEmail: email,\n priceId: product.storePriceId,\n }\n\n if (validateOnly) body.validateOnly = true\n\n const response = await fetch(`${apiBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n\n const result = await response.json()\n\n if (!result.success) {\n throw new Error(result.error || 'Failed to create intent')\n }\n\n setStripePromise(loadStripe(result.publishableKey))\n setClientSecret(result.clientSecret)\n variableStore.set('user.stripeCustomerId', result.customerId)\n\n tracker.track('checkout.start', {\n productId: product.id,\n priceId: product.stripePriceId || product.storePriceId,\n productName: product.displayName,\n })\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : 'Failed to initialize payment'\n setError(msg)\n variableStore.set('payment.error', msg)\n } finally {\n setIsLoading(false)\n variableStore.set('payment.loading', false)\n }\n }\n\n createIntent()\n }, [email, campaignId, product, paymentMode, validateOnly, tracker, variableStore, apiBaseUrl])\n\n if (isLoading) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>Loading payment form...</div>\n }\n\n if (!email) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#ef4444', fontSize: '14px' }}>Email is required to initialize payment</div>\n }\n\n if (error) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#ef4444', fontSize: '14px' }}>{error}</div>\n }\n\n if (!stripePromise || !clientSecret) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>Initializing payment...</div>\n }\n\n const defaultAppearance: Appearance = {\n theme: 'stripe',\n variables: { colorPrimary: '#3b82f6', borderRadius: '8px' },\n }\n\n return (\n <div className={className}>\n <Elements stripe={stripePromise} options={{ clientSecret, appearance: appearance || defaultAppearance }}>\n <InnerPaymentForm\n paymentMode={paymentMode}\n validateOnly={validateOnly}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Elements>\n </div>\n )\n}\n","import { useEffect, useRef, useCallback } from 'react'\nimport { useFunnelContext } from './FunnelProvider'\n\nexport interface PaddleCheckoutProps {\n /** Product ID to checkout (default: currently selected product) */\n productId?: string\n /** Display mode: overlay opens Paddle in a modal, inline renders embedded */\n mode?: 'overlay' | 'inline'\n /** Called on successful checkout */\n onSuccess?: () => void\n /** Called on checkout error */\n onError?: (error: string) => void\n /** Additional CSS class */\n className?: string\n}\n\ndeclare global {\n interface Window {\n Paddle?: {\n Setup: (options: Record<string, unknown>) => void\n Checkout: {\n open: (options: Record<string, unknown>) => void\n }\n }\n }\n}\n\n/**\n * Paddle checkout component.\n * Supports overlay (modal) and inline (embedded) modes.\n */\nexport function PaddleCheckout({\n productId,\n mode = 'overlay',\n onSuccess,\n onError,\n className,\n}: PaddleCheckoutProps) {\n const { variableStore, tracker, products } = useFunnelContext()\n const containerRef = useRef<HTMLDivElement>(null)\n const initializedRef = useRef(false)\n\n // Resolve product\n const product = productId\n ? products.find((p) => p.id === productId)\n : products.find((p) => p.id === (variableStore.get('products.selectedProductId') as string))\n\n const handleCheckoutComplete = useCallback(() => {\n tracker.track('purchase.complete', {\n amount: product?.rawPrice ? product.rawPrice / 100 : 0,\n currency: product?.currencyCode || 'USD',\n })\n onSuccess?.()\n }, [tracker, product, onSuccess])\n\n useEffect(() => {\n if (initializedRef.current || !product?.paddlePriceId) return\n initializedRef.current = true\n\n if (!window.Paddle) {\n onError?.('Paddle.js not loaded. Include the Paddle script in your HTML.')\n return\n }\n\n const email = variableStore.get('user.email') as string || ''\n\n if (mode === 'overlay') {\n window.Paddle.Checkout.open({\n items: [{ priceId: product.paddlePriceId, quantity: 1 }],\n customer: email ? { email } : undefined,\n successCallback: handleCheckoutComplete,\n closeCallback: () => { /* user closed */ },\n })\n } else {\n // Inline mode\n if (containerRef.current) {\n window.Paddle.Checkout.open({\n items: [{ priceId: product.paddlePriceId, quantity: 1 }],\n customer: email ? { email } : undefined,\n settings: {\n displayMode: 'inline',\n frameTarget: containerRef.current.id || 'paddle-checkout',\n frameInitialHeight: 450,\n frameStyle: 'width: 100%; min-width: 312px; background-color: transparent; border: none;',\n },\n successCallback: handleCheckoutComplete,\n })\n }\n }\n\n tracker.track('checkout.start', {\n productId: product.id,\n priceId: product.paddlePriceId,\n productName: product.displayName,\n })\n }, [product, mode, variableStore, tracker, handleCheckoutComplete, onError])\n\n if (!product) {\n return (\n <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#ef4444', fontSize: '14px' }}>\n No product selected\n </div>\n )\n }\n\n if (mode === 'inline') {\n return <div ref={containerRef} id=\"paddle-checkout\" className={className} />\n }\n\n // Overlay mode renders nothing visible\n return null\n}\n"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/runtime/integrations.ts","../src/components/FunnelProvider.tsx","../src/hooks/useVariable.ts","../src/hooks/useVariables.ts","../src/hooks/useUser.ts","../src/hooks/useResponse.ts","../src/hooks/useQueryParams.ts","../src/hooks/useData.ts","../src/hooks/useLocale.ts","../src/hooks/useTranslation.ts","../src/hooks/useNavigation.ts","../src/hooks/useProducts.ts","../src/hooks/useTracking.ts","../src/hooks/usePayment.ts","../src/hooks/useFunnel.ts","../src/components/PaymentForm.tsx","../src/components/PaddleCheckout.tsx"],"names":["createContext","useContext","useCallback","useSyncExternalStore","useMemo","useStripe","useElements","useState","response","result","useEffect","jsx","PaymentElement","useRef","loadStripe","Elements"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AppFunnelConfig, PageDefinition } from './types'\n\n/**\n * Type helper for appfunnel.config.ts.\n * Returns the config object unchanged — exists purely for TypeScript autocomplete.\n */\nexport function defineConfig(config: AppFunnelConfig): AppFunnelConfig {\n return config\n}\n\n/**\n * Define page metadata co-located with the page component.\n * Export this from your page file alongside the default React component.\n *\n * @example\n * ```tsx\n * // pages/quiz.tsx\n * import { definePage, useVariable, useNavigation } from '@appfunnel-dev/sdk'\n *\n * export const page = definePage({\n * name: 'Quiz',\n * type: 'default',\n * routes: [\n * { to: 'checkout', when: { variable: 'plan', equals: 'premium' } },\n * { to: 'success' }, // fallback\n * ],\n * })\n *\n * export default function Quiz() {\n * // ...\n * }\n * ```\n *\n * The CLI build step collects all `page` exports and assembles them into\n * the full config (pages map + routes map + computed route manifest for analytics).\n */\nexport function definePage(definition: PageDefinition): PageDefinition {\n return definition\n}\n","/**\n * Integration runtime — sets up window.appfunnel event bus and initializes\n * third-party integrations (Meta Pixel, GTM, Clarity, etc.).\n *\n * The integration loaders from the admin codebase subscribe to events via\n * window.appfunnel.on(). The FunnelTracker emits events via _emitEvent().\n * This module bridges the two by setting up the pub/sub layer.\n */\n\nimport type { VariableValue } from '../types'\nimport type { VariableStore } from './variableStore'\nimport type { Router } from './router'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Integration config map: integrationId -> config object */\nexport type IntegrationConfigs = Record<string, Record<string, unknown>>\n\ntype EventCallback = (data: unknown) => void\n\ninterface Subscription {\n callback: EventCallback\n scope: 'global' | 'page'\n}\n\n// ============================================================================\n// AppFunnel Runtime (window.appfunnel event bus)\n// ============================================================================\n\nexport class AppFunnelEventBus {\n private subscriptions = new Map<string, Subscription[]>()\n private store: VariableStore\n private router: Router\n private selectProduct: (productId: string) => void\n\n constructor(\n store: VariableStore,\n router: Router,\n selectProduct: (productId: string) => void,\n ) {\n this.store = store\n this.router = router\n this.selectProduct = selectProduct\n }\n\n /** Attach the event bus to window.appfunnel */\n attach(): void {\n if (typeof window === 'undefined') return\n\n const self = this\n\n ;(window as unknown as Record<string, unknown>).appfunnel = {\n // Event subscriptions\n on(eventType: string, callback: EventCallback): () => void {\n return self.on(eventType, callback)\n },\n off(eventType: string, callback: EventCallback): void {\n self.off(eventType, callback)\n },\n\n // Internal — called by FunnelTracker.emitToRuntime()\n _emitEvent(eventType: string, data?: unknown): void {\n self.emit(eventType, data)\n },\n\n // Getters for integration loaders that need them\n getVariable(variableId: string): VariableValue {\n return self.store.get(variableId)\n },\n getVariables(): Record<string, VariableValue> {\n return { ...self.store.getState() }\n },\n getCurrentPageId(): string | null {\n return self.router.getCurrentPage()?.key ?? null\n },\n getCustomerId(): string | null {\n return (self.store.get('user.stripeCustomerId') as string) || null\n },\n isPaymentAuthorized(): boolean {\n return !!(self.store.get('user.stripeCustomerId') as string)\n },\n\n // Methods\n setVariable(variableId: string, value: VariableValue): void {\n self.store.set(variableId, value)\n },\n selectProduct(productId: string): void {\n self.selectProduct(productId)\n },\n goToNextPage(): void {\n self.router.goToNextPage(self.store.getState())\n },\n goBack(): void {\n self.router.goBack()\n },\n openUrl(url: string): void {\n if (url) window.open(url, '_blank', 'noopener,noreferrer')\n },\n callEvent(eventName: string, data?: Record<string, unknown>): void {\n self.emit(eventName, data)\n },\n\n // Debug\n debug: false,\n setDebug(_enabled: boolean): void { /* noop in SDK */ },\n }\n }\n\n /** Emit an event to all subscribers */\n emit(eventType: string, data?: unknown): void {\n const subs = this.subscriptions.get(eventType)\n if (!subs || subs.length === 0) return\n\n for (const sub of subs) {\n try {\n sub.callback(data)\n } catch (error) {\n console.error(`[AppFunnel] Error in event handler for \"${eventType}\":`, error)\n }\n }\n }\n\n /** Clean up page-scoped subscriptions (called on page change) */\n onPageChange(): void {\n for (const [eventType, subs] of this.subscriptions.entries()) {\n this.subscriptions.set(eventType, subs.filter((s) => s.scope === 'global'))\n }\n }\n\n /** Destroy and detach from window */\n destroy(): void {\n this.subscriptions.clear()\n if (typeof window !== 'undefined') {\n delete (window as unknown as Record<string, unknown>).appfunnel\n }\n }\n\n private on(eventType: string, callback: EventCallback): () => void {\n if (!this.subscriptions.has(eventType)) {\n this.subscriptions.set(eventType, [])\n }\n const sub: Subscription = { callback, scope: 'global' }\n this.subscriptions.get(eventType)!.push(sub)\n return () => this.off(eventType, callback)\n }\n\n private off(eventType: string, callback: EventCallback): void {\n const subs = this.subscriptions.get(eventType)\n if (!subs) return\n const index = subs.findIndex((s) => s.callback === callback)\n if (index > -1) subs.splice(index, 1)\n }\n}\n\n// ============================================================================\n// Integration Loader Registry\n// ============================================================================\n\ntype IntegrationLoader = (config: Record<string, unknown>) => void\n\nconst loaders: Record<string, IntegrationLoader> = {}\n\n/**\n * Register a custom integration loader.\n * Called by the CLI build or user code to add integrations.\n */\nexport function registerIntegration(id: string, loader: IntegrationLoader): void {\n loaders[id] = loader\n}\n\n/**\n * Initialize all integrations from config.\n * Must be called after AppFunnelEventBus.attach() so window.appfunnel exists.\n */\nexport function initializeIntegrations(integrations: IntegrationConfigs): void {\n if (typeof window === 'undefined') return\n\n ;(window as unknown as Record<string, unknown>).__INTEGRATIONS__ = integrations\n\n for (const [integrationId, config] of Object.entries(integrations)) {\n const loader = loaders[integrationId]\n if (loader) {\n try {\n loader(config)\n } catch (err) {\n console.error(`[AppFunnel] Error loading integration ${integrationId}:`, err)\n }\n }\n }\n}\n","import { createContext, useContext, useEffect, useRef, useMemo, useCallback } from 'react'\nimport type {\n AppFunnelConfig,\n VariableValue,\n RuntimeProduct,\n EnrichedPriceData,\n} from '../types'\nimport { VariableStore, createVariableStore } from '../runtime/variableStore'\nimport { Router } from '../runtime/router'\nimport { FunnelTracker } from '../runtime/tracker'\nimport { buildRuntimeProducts } from '../runtime/products'\nimport { computeSystemVariables, startSystemVariableUpdater } from '../runtime/systemVariables'\nimport { AppFunnelEventBus, initializeIntegrations } from '../runtime/integrations'\nimport { I18n, type TranslationMap } from '../runtime/i18n'\n\n// ============================================================================\n// Context\n// ============================================================================\n\nexport interface FunnelContextValue {\n config: AppFunnelConfig\n variableStore: VariableStore\n router: Router\n tracker: FunnelTracker\n i18n: I18n\n products: RuntimeProduct[]\n selectedProductId: string | null\n selectProduct: (productId: string) => void\n funnelId: string\n campaignId: string\n sessionId: string | null\n apiBaseUrl: string\n}\n\nconst FunnelContext = createContext<FunnelContextValue | null>(null)\n\nexport function useFunnelContext(): FunnelContextValue {\n const ctx = useContext(FunnelContext)\n if (!ctx) {\n throw new Error('useFunnelContext must be used within a <FunnelProvider>')\n }\n return ctx\n}\n\n// ============================================================================\n// Provider Props\n// ============================================================================\n\nexport interface FunnelProviderProps {\n config: AppFunnelConfig\n children: React.ReactNode\n /** Pre-fetched session data (from API) */\n sessionData?: {\n sessionId?: string\n campaignId: string\n funnelId: string\n variables?: Record<string, VariableValue>\n customerId?: string\n experimentId?: string | null\n }\n /** Pre-fetched enriched price data map: storePriceId → price data */\n priceData?: Map<string, EnrichedPriceData>\n /** API base URL override */\n apiBaseUrl?: string\n /** Campaign slug for session cookies */\n campaignSlug?: string\n /** Override the initial page (e.g. from URL slug on reload/deep link) */\n initialPage?: string\n /** Translations map: { \"en\": { \"key\": \"value\" }, \"de\": { \"key\": \"wert\" } } */\n translations?: TranslationMap\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport function FunnelProvider({\n config,\n children,\n sessionData,\n priceData,\n apiBaseUrl = '',\n campaignSlug,\n initialPage,\n translations,\n}: FunnelProviderProps) {\n const campaignId = sessionData?.campaignId || config.projectId\n const funnelId = sessionData?.funnelId || config.projectId\n\n // ── Initialize runtime objects (once) ─────────────\n const storeRef = useRef<VariableStore | null>(null)\n const routerRef = useRef<Router | null>(null)\n const trackerRef = useRef<FunnelTracker | null>(null)\n const eventBusRef = useRef<AppFunnelEventBus | null>(null)\n const i18nRef = useRef<I18n | null>(null)\n\n if (!storeRef.current) {\n storeRef.current = createVariableStore(\n { responses: config.responses, queryParams: config.queryParams, data: config.data },\n sessionData?.variables,\n )\n }\n if (!routerRef.current) {\n routerRef.current = new Router(config, initialPage)\n }\n if (!trackerRef.current) {\n trackerRef.current = new FunnelTracker(apiBaseUrl)\n }\n if (!i18nRef.current) {\n const i18n = new I18n(config.defaultLocale || 'en')\n if (translations) i18n.load(translations)\n // Auto-detect locale from browser if available\n if (typeof navigator !== 'undefined') {\n const browserLang = navigator.language?.split('-')[0]\n if (browserLang && translations?.[browserLang]) {\n i18n.setLocale(browserLang)\n }\n }\n i18nRef.current = i18n\n }\n\n const store = storeRef.current\n const router = routerRef.current\n const tracker = trackerRef.current\n const i18n = i18nRef.current\n\n // ── Build products ────────────────────────────────\n const products = useMemo(() => {\n if (!config.products?.items || !priceData) return []\n return buildRuntimeProducts(config.products.items, priceData)\n }, [config.products, priceData])\n\n // ── Selected product ──────────────────────────────\n const defaultProductId = config.products?.defaultId || products[0]?.id || null\n const selectedProductIdRef = useRef<string | null>(defaultProductId)\n\n const selectProduct = useCallback((productId: string) => {\n selectedProductIdRef.current = productId\n store.set('products.selectedProductId', productId)\n }, [store])\n\n // ── Event bus + integrations ──────────────────────\n useEffect(() => {\n const eventBus = new AppFunnelEventBus(store, router, selectProduct)\n eventBus.attach()\n eventBusRef.current = eventBus\n\n // Initialize third-party integrations (Meta Pixel, GTM, Clarity, etc.)\n if (config.integrations && Object.keys(config.integrations).length > 0) {\n initializeIntegrations(config.integrations)\n }\n\n return () => {\n eventBus.destroy()\n eventBusRef.current = null\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Initialize tracker ────────────────────────────\n useEffect(() => {\n tracker.init(campaignId, funnelId, campaignSlug, sessionData?.experimentId)\n\n if (sessionData?.sessionId) {\n tracker.setSessionId(sessionData.sessionId)\n }\n\n // Fire initial events\n const currentPage = router.getCurrentPage()\n tracker.track('funnel.start')\n if (currentPage) {\n tracker.track('page.view', {\n pageId: currentPage.key,\n pageKey: currentPage.key,\n pageName: currentPage.name,\n isInitial: true,\n })\n tracker.startPageTracking(currentPage.key)\n }\n\n return () => {\n tracker.stopPageTracking()\n tracker.flushVariables()\n }\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── System variables ──────────────────────────────\n const sessionStartTime = useRef(Date.now())\n const pageStartTime = useRef(Date.now())\n\n useEffect(() => {\n const sysVars = computeSystemVariables({\n currentPageKey: router.getCurrentPage()?.key || '',\n pageHistory: router.getPageHistory(),\n pageStartTime: pageStartTime.current,\n sessionStartTime: sessionStartTime.current,\n totalPages: Object.keys(config.pages ?? {}).length,\n funnelId,\n campaignId,\n })\n store.setMany(sysVars)\n\n if (defaultProductId) {\n store.set('products.selectedProductId', defaultProductId)\n }\n\n const stopUpdater = startSystemVariableUpdater(store, () => ({\n currentPageKey: router.getCurrentPage()?.key || '',\n pageHistory: router.getPageHistory(),\n pageStartTime: pageStartTime.current,\n sessionStartTime: sessionStartTime.current,\n totalPages: Object.keys(config.pages ?? {}).length,\n funnelId,\n campaignId,\n }))\n\n return stopUpdater\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── Sync variables to tracker for persistence ─────\n useEffect(() => {\n return store.subscribe(() => {\n tracker.setCurrentVariables(store.getState() as Record<string, unknown>)\n })\n }, [store, tracker])\n\n // ── Context value ─────────────────────────────────\n const contextValue = useMemo<FunnelContextValue>(() => ({\n config,\n variableStore: store,\n router,\n tracker,\n i18n,\n products,\n selectedProductId: selectedProductIdRef.current,\n selectProduct,\n funnelId,\n campaignId,\n sessionId: tracker.getSessionId(),\n apiBaseUrl,\n }), [config, store, router, tracker, i18n, products, selectProduct, funnelId, campaignId, apiBaseUrl])\n\n return (\n <FunnelContext.Provider value={contextValue}>\n {children}\n </FunnelContext.Provider>\n )\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read/write a single variable.\n *\n * ```tsx\n * const [email, setEmail] = useVariable<string>('email')\n * const [count, setCount] = useVariable<number>('count')\n * const [agreed, setAgreed] = useVariable<boolean>('agreed')\n * const [tags, setTags] = useVariable<string[]>('tags')\n * ```\n */\nexport function useVariable<T extends VariableValue>(\n id: string,\n): [T, (value: T) => void] {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (callback: () => void) => variableStore.subscribe(callback),\n [variableStore],\n )\n\n const getSnapshot = useCallback(\n () => variableStore.get(id) as T,\n [variableStore, id],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: T) => variableStore.set(id, v),\n [variableStore, id],\n )\n\n return [value, setValue]\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read all variables (including system variables). Read-only.\n * Use useVariable() to write individual variables.\n */\nexport function useVariables(): Record<string, VariableValue> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (callback: () => void) => variableStore.subscribe(callback),\n [variableStore],\n )\n\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { UserState } from '../types'\n\n/**\n * Read built-in user state (email, name, customerId).\n *\n * For reading/writing arbitrary user fields, use `useUserProperty('fieldName')`.\n */\nexport function useUser(): UserState {\n\tconst { variableStore, tracker } = useFunnelContext()\n\n\tconst subscribe = useCallback(\n\t\t(cb: () => void) => variableStore.subscribe(cb),\n\t\t[variableStore]\n\t)\n\tconst getSnapshot = useCallback(\n\t\t() => variableStore.getState(),\n\t\t[variableStore]\n\t)\n\tconst variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n\treturn useMemo(\n\t\t() => ({\n\t\t\temail: (variables['user.email'] as string) || '',\n\t\t\tname: (variables['user.name'] as string) || '',\n\t\t\tstripeCustomerId:\n\t\t\t\t(variables['user.stripeCustomerId'] as string) || '',\n\t\t\tpaddleCustomerId:\n\t\t\t\t(variables['user.paddleCustomerId'] as string) || '',\n\t\t\tdateOfBirth: (variables['user.dateOfBirth'] as string) || '',\n\n\t\t\tsetEmail(email: string) {\n\t\t\t\tvariableStore.set('user.email', email)\n\t\t\t\ttracker.identify(email)\n\t\t\t},\n\t\t\tsetName(name: string) {\n\t\t\t\tvariableStore.set('user.name', name)\n\t\t\t},\n\t\t\tsetDateOfBirth(dateOfBirth: string) {\n\t\t\t\tvariableStore.set('user.dateOfBirth', dateOfBirth)\n\t\t\t},\n\t\t}),\n\t\t[variables, variableStore, tracker]\n\t)\n}\n\n/**\n * Read/write a user property by field name.\n * Auto-prefixes with `user.` — no need to define in config.\n *\n * ```tsx\n * const [dob, setDob] = useUserProperty('dateOfBirth')\n * const [gender, setGender] = useUserProperty('gender')\n * ```\n */\nexport function useUserProperty(\n\tfield: string\n): [string, (value: string) => void] {\n\tconst { variableStore } = useFunnelContext()\n\tconst key = `user.${field}`\n\n\tconst subscribe = useCallback(\n\t\t(cb: () => void) => variableStore.subscribe(cb),\n\t\t[variableStore]\n\t)\n\tconst getSnapshot = useCallback(\n\t\t() => (variableStore.get(key) as string) || '',\n\t\t[variableStore, key]\n\t)\n\n\tconst value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n\tconst setValue = useCallback(\n\t\t(v: string) => variableStore.set(key, v),\n\t\t[variableStore, key]\n\t)\n\n\treturn [value, setValue]\n}\n","import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read/write a single response variable (answers.*).\n *\n * ```tsx\n * const [goal, setGoal] = useResponse<string>('goal')\n * const [interests, setInterests] = useResponse<string[]>('interests')\n * ```\n */\nexport function useResponse<T extends VariableValue>(\n key: string,\n): [T, (value: T) => void] {\n const { variableStore } = useFunnelContext()\n const prefixedKey = `answers.${key}`\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.get(prefixedKey) as T,\n [variableStore, prefixedKey],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: T) => variableStore.set(prefixedKey, v),\n [variableStore, prefixedKey],\n )\n\n return [value, setValue]\n}\n\n/**\n * Read all response variables as a flat object (without the `answers.` prefix).\n *\n * ```tsx\n * const responses = useResponses()\n * // { goal: 'weight_loss', interests: ['yoga', 'running'] }\n * ```\n */\nexport function useResponses(): Record<string, VariableValue> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const result: Record<string, VariableValue> = {}\n for (const [key, value] of Object.entries(variables)) {\n if (key.startsWith('answers.')) {\n result[key.slice(8)] = value\n }\n }\n return result\n }, [variables])\n}\n","import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\n\n/**\n * Read all URL query parameters as a flat object (without the `query.` prefix).\n *\n * `query.*` variables are auto-populated from `window.location.search`.\n * e.g. `?utm_source=google&ref=abc` → `{ utm_source: 'google', ref: 'abc' }`.\n *\n * These are read-only from the developer's perspective — they come from the URL.\n */\nexport function useQueryParams(): Record<string, string> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const params: Record<string, string> = {}\n for (const [key, value] of Object.entries(variables)) {\n if (key.startsWith('query.') && typeof value === 'string') {\n params[key.slice(6)] = value\n }\n }\n return params\n }, [variables])\n}\n\n/**\n * Read a single query parameter by name.\n *\n * ```tsx\n * const utmSource = useQueryParam('utm_source')\n * ```\n */\nexport function useQueryParam(key: string): string {\n const { variableStore } = useFunnelContext()\n const prefixedKey = `query.${key}`\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => (variableStore.get(prefixedKey) as string) || '',\n [variableStore, prefixedKey],\n )\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read/write a single data variable (data.*).\n *\n * ```tsx\n * const [tier, setTier] = useData<string>('selectedPlanTier')\n * const [seen, setSeen] = useData<boolean>('hasSeenOnboarding')\n * ```\n */\nexport function useData<T extends VariableValue>(\n key: string,\n): [T, (value: T) => void] {\n const { variableStore } = useFunnelContext()\n const prefixedKey = `data.${key}`\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.get(prefixedKey) as T,\n [variableStore, prefixedKey],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: T) => variableStore.set(prefixedKey, v),\n [variableStore, prefixedKey],\n )\n\n return [value, setValue]\n}\n","import { useMemo } from 'react'\nimport type { LocaleState } from '../types'\n\n/**\n * Get the user's locale from the browser.\n *\n * Provides language, region, and currency info derived from the browser.\n * Combine with i18n libraries (react-i18next, next-intl, etc.) for translations.\n *\n * ```tsx\n * const { language, region, currency } = useLocale()\n * // language: 'en', region: 'US', currency: 'USD'\n * ```\n */\nexport function useLocale(): LocaleState {\n return useMemo(() => {\n if (typeof navigator === 'undefined') {\n return {\n locale: 'en-US',\n language: 'en',\n region: 'US',\n languages: ['en-US'],\n timeZone: 'UTC',\n is24Hour: false,\n }\n }\n\n const locale = navigator.language || 'en-US'\n const [language, region] = locale.split('-')\n const languages = [...(navigator.languages || [locale])]\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'\n const is24Hour = detect24Hour(locale)\n\n return {\n locale,\n language: language || 'en',\n region: region?.toUpperCase() || 'US',\n languages,\n timeZone,\n is24Hour,\n }\n }, [])\n}\n\n/** Detect if locale likely uses 24h clock */\nfunction detect24Hour(locale: string): boolean {\n try {\n const formatted = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).format(new Date())\n return !formatted.match(/am|pm/i)\n } catch {\n return false\n }\n}\n","import { useSyncExternalStore, useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { TranslationState } from '../types'\n\n/**\n * Access translations for the current locale.\n *\n * ```tsx\n * const { t, locale, setLocale } = useTranslation()\n *\n * return (\n * <div>\n * <h1>{t('welcome', { name: 'John' })}</h1>\n * <button onClick={() => setLocale('de')}>Deutsch</button>\n * </div>\n * )\n * ```\n */\nexport function useTranslation(): TranslationState {\n const { i18n } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => i18n.subscribe(cb),\n [i18n],\n )\n const getSnapshot = useCallback(\n () => i18n.getLocale(),\n [i18n],\n )\n\n const locale = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const t = useCallback(\n (key: string, params?: Record<string, string | number>) => i18n.t(key, params),\n [i18n, locale], // eslint-disable-line react-hooks/exhaustive-deps\n )\n\n const setLocale = useCallback(\n (l: string) => i18n.setLocale(l),\n [i18n],\n )\n\n const availableLocales = i18n.getAvailableLocales()\n\n return { t, locale, setLocale, availableLocales }\n}\n","import { useCallback, useSyncExternalStore } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { NavigationState } from '../types'\n\n/**\n * Navigation hook — evaluates routes, navigates between pages, tracks progress.\n */\nexport function useNavigation(): NavigationState {\n const { router, variableStore, tracker } = useFunnelContext()\n\n // Re-render when variables change (routes depend on variable state)\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const goToNextPage = useCallback(() => {\n const previousPage = router.getCurrentPage()\n if (previousPage) {\n tracker.stopPageTracking()\n }\n\n const nextKey = router.goToNextPage(variables)\n if (nextKey) {\n const nextPage = router.getCurrentPage()\n if (nextPage) {\n tracker.track('page.view', {\n pageId: nextPage.key,\n pageKey: nextPage.key,\n pageName: nextPage.name,\n })\n tracker.startPageTracking(nextPage.key)\n }\n // Update system variables\n variableStore.setMany({\n 'page.currentId': nextKey,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n 'page.timeOnCurrent': 0,\n })\n }\n }, [router, variables, tracker, variableStore])\n\n const goBack = useCallback(() => {\n tracker.stopPageTracking()\n const prevKey = router.goBack()\n if (prevKey) {\n const page = router.getCurrentPage()\n if (page) {\n tracker.track('page.view', {\n pageId: page.key,\n pageKey: page.key,\n pageName: page.name,\n })\n tracker.startPageTracking(page.key)\n }\n variableStore.setMany({\n 'page.currentId': prevKey,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n 'page.timeOnCurrent': 0,\n })\n }\n }, [router, tracker, variableStore])\n\n const goToPage = useCallback((pageKey: string) => {\n tracker.stopPageTracking()\n const key = router.goToPage(pageKey)\n if (key) {\n const page = router.getCurrentPage()\n if (page) {\n tracker.track('page.view', {\n pageId: page.key,\n pageKey: page.key,\n pageName: page.name,\n })\n tracker.startPageTracking(page.key)\n }\n variableStore.setMany({\n 'page.currentId': key,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n 'page.timeOnCurrent': 0,\n })\n }\n }, [router, tracker, variableStore])\n\n return {\n goToNextPage,\n goBack,\n goToPage,\n currentPage: router.getCurrentPage(),\n pageHistory: router.getPageHistory(),\n progress: router.getProgress(),\n }\n}\n","import { useCallback, useSyncExternalStore } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { ProductsState } from '../types'\n\n/**\n * Products hook — access product list, selected product, and selection handler.\n */\nexport function useProducts(): ProductsState {\n const { products, variableStore, selectProduct: ctxSelect } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.get('products.selectedProductId') as string | null,\n [variableStore],\n )\n\n const selectedId = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const selected = products.find((p) => p.id === selectedId) || null\n\n const select = useCallback((productId: string) => {\n ctxSelect(productId)\n }, [ctxSelect])\n\n return { products, selected, select }\n}\n","import { useCallback } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { TrackingState } from '../types'\n\n/**\n * Tracking hook — fire events and identify users.\n */\nexport function useTracking(): TrackingState {\n const { tracker } = useFunnelContext()\n\n const track = useCallback(\n (eventName: string, data?: Record<string, unknown>) => {\n tracker.track(eventName, data)\n },\n [tracker],\n )\n\n const identify = useCallback(\n (email: string) => {\n tracker.identify(email)\n },\n [tracker],\n )\n\n return { track, identify }\n}\n","import { useCallback, useSyncExternalStore, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { PaymentState } from '../types'\n\n/**\n * Payment hook — reads payment-related system variables.\n */\nexport function usePayment(): PaymentState {\n const { variableStore, tracker } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const last4 = variables['card.last4'] as string || ''\n const brand = variables['card.brand'] as string || ''\n const expMonth = variables['card.expMonth'] as number || 0\n const expYear = variables['card.expYear'] as number || 0\n\n return {\n customerId: tracker.getCustomerId(),\n isAuthorized: !!last4,\n loading: !!variables['payment.loading'],\n error: (variables['payment.error'] as string) || null,\n cardDetails: last4\n ? { last4, brand, expMonth, expYear }\n : null,\n }\n }, [variables, tracker])\n}\n","import { useFunnelContext } from '../components/FunnelProvider'\nimport { useVariables } from './useVariables'\nimport { useUser } from './useUser'\nimport { useResponses } from './useResponse'\nimport { useQueryParams } from './useQueryParams'\nimport { useNavigation } from './useNavigation'\nimport { useProducts } from './useProducts'\nimport { useTracking } from './useTracking'\nimport { usePayment } from './usePayment'\nimport type { FunnelState } from '../types'\n\n/**\n * Convenience hook that combines all SDK hooks.\n * Useful for simple funnels where you don't want multiple hook imports.\n */\nexport function useFunnel(): FunnelState {\n const { funnelId, campaignId, tracker } = useFunnelContext()\n\n return {\n funnelId,\n campaignId,\n sessionId: tracker.getSessionId(),\n variables: useVariables(),\n user: useUser(),\n responses: useResponses(),\n queryParams: useQueryParams(),\n navigation: useNavigation(),\n products: useProducts(),\n tracking: useTracking(),\n payment: usePayment(),\n }\n}\n","import { useEffect, useState, useRef, useCallback, useMemo } from 'react'\nimport { loadStripe, type Stripe, type Appearance } from '@stripe/stripe-js'\nimport {\n Elements,\n PaymentElement,\n useStripe,\n useElements,\n} from '@stripe/react-stripe-js'\nimport { useFunnelContext } from './FunnelProvider'\nimport { useVariable } from '../hooks/useVariable'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PaymentFormProps {\n /** Product ID override (default: currently selected product) */\n productId?: string\n /** \"checkout\" for full payment, \"validate-only\" to just collect card */\n mode?: 'checkout' | 'validate-only'\n /** Called on successful payment */\n onSuccess?: () => void\n /** Called on payment error */\n onError?: (error: string) => void\n /** Allow Stripe promotion codes */\n allowPromotionCodes?: boolean\n /** Additional CSS class */\n className?: string\n /** Stripe Appearance override */\n appearance?: Appearance\n}\n\n// ============================================================================\n// Inner Form (uses Stripe hooks)\n// ============================================================================\n\nfunction InnerPaymentForm({\n paymentMode,\n validateOnly,\n onSuccess,\n onError,\n}: {\n paymentMode: 'setup' | 'payment'\n validateOnly: boolean\n onSuccess?: () => void\n onError?: (error: string) => void\n}) {\n const stripe = useStripe()\n const elements = useElements()\n const [error, setError] = useState<string | null>(null)\n const { variableStore, campaignId, tracker, apiBaseUrl, products } = useFunnelContext()\n\n const handleSubmit = useCallback(async () => {\n if (!stripe || !elements) {\n const msg = 'Stripe not loaded'\n setError(msg)\n onError?.(msg)\n return\n }\n\n setError(null)\n variableStore.set('payment.loading', true)\n\n try {\n const confirmFn = paymentMode === 'setup' ? stripe.confirmSetup : stripe.confirmPayment\n const confirmResult = await confirmFn({\n elements,\n redirect: 'if_required',\n confirmParams: { return_url: window.location.href },\n })\n\n if (confirmResult.error) {\n const msg = confirmResult.error.message || 'Payment failed'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n tracker.track('checkout.payment_added')\n\n if (validateOnly) {\n const piId = 'paymentIntent' in confirmResult\n ? (confirmResult as Record<string, unknown>).paymentIntent as { id?: string } | undefined\n : undefined\n\n if (!piId?.id) {\n const msg = 'PaymentIntent not found after confirmation'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n const response = await fetch(\n `${apiBaseUrl}/campaign/${campaignId}/stripe/validate-card`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n campaignId,\n sessionId: tracker.getSessionId(),\n paymentIntentId: piId.id,\n }),\n },\n )\n\n const result = await response.json()\n\n if (!result.success) {\n const msg = result.error || 'Card validation failed'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n variableStore.setMany({\n 'card.last4': result.card.last4,\n 'card.brand': result.card.brand,\n 'card.expMonth': result.card.expMonth,\n 'card.expYear': result.card.expYear,\n 'card.funding': result.card.funding,\n 'payment.error': '',\n })\n\n onSuccess?.()\n return\n }\n\n // ── Normal purchase path ──\n const paymentIntentId = 'paymentIntent' in confirmResult\n ? ((confirmResult as Record<string, unknown>).paymentIntent as { id?: string })?.id\n : undefined\n\n const selectedId = variableStore.get('products.selectedProductId') as string\n const product = products.find((p) => p.id === selectedId)\n\n if (!product?.stripePriceId) {\n const msg = 'No product selected or missing Stripe price'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n return\n }\n\n const variables = variableStore.getState()\n await tracker.updateUserData(variables as Record<string, unknown>)\n\n const response = await fetch(\n `${apiBaseUrl}/campaign/${campaignId}/stripe/purchase`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n campaignId,\n sessionId: tracker.getSessionId(),\n stripePriceId: product.stripePriceId,\n trialPeriodDays: product.hasTrial ? product.trialDays : undefined,\n onSessionPiId: paymentMode === 'payment' ? paymentIntentId : undefined,\n }),\n },\n )\n\n const result = await response.json()\n\n if (result.success) {\n variableStore.set('payment.error', '')\n if (result.eventId || result.eventIds?.firstPeriod) {\n tracker.track('purchase.complete', {\n amount: product.rawPrice ? product.rawPrice / 100 : 0,\n currency: product.currencyCode || 'USD',\n })\n }\n onSuccess?.()\n } else {\n const msg = result.error || 'Failed to process payment'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : 'An error occurred'\n setError(msg)\n variableStore.set('payment.error', msg)\n onError?.(msg)\n } finally {\n variableStore.set('payment.loading', false)\n }\n }, [stripe, elements, paymentMode, validateOnly, variableStore, campaignId, tracker, apiBaseUrl, products, onSuccess, onError])\n\n // Register submit handler globally for external triggering\n useEffect(() => {\n if (typeof window !== 'undefined') {\n ;(window as unknown as Record<string, unknown>).__paymentElementSubmit = handleSubmit\n }\n return () => {\n if (typeof window !== 'undefined') {\n delete (window as unknown as Record<string, unknown>).__paymentElementSubmit\n }\n }\n }, [handleSubmit])\n\n return (\n <div>\n <PaymentElement options={{ layout: 'tabs' }} />\n {error && (\n <div style={{ color: '#ef4444', fontSize: '14px', marginTop: '12px' }}>\n {error}\n </div>\n )}\n </div>\n )\n}\n\n// ============================================================================\n// PaymentForm (public component)\n// ============================================================================\n\nexport function PaymentForm({\n productId,\n mode = 'checkout',\n onSuccess,\n onError,\n className,\n appearance,\n}: PaymentFormProps) {\n const { campaignId, tracker, variableStore, apiBaseUrl, products } = useFunnelContext()\n const [email] = useVariable<string>('user.email')\n\n const validateOnly = mode === 'validate-only'\n\n // Resolve the product\n const product = useMemo(() => {\n if (productId) return products.find((p) => p.id === productId) || null\n const selectedId = variableStore.get('products.selectedProductId') as string\n return products.find((p) => p.id === selectedId) || null\n }, [productId, products, variableStore])\n\n // Derive payment mode from product\n const paymentMode = useMemo((): 'setup' | 'payment' => {\n if (validateOnly) return 'payment'\n if (product?.hasTrial && !product.paidTrial) return 'setup'\n return 'payment'\n }, [product, validateOnly])\n\n const [stripePromise, setStripePromise] = useState<Promise<Stripe | null> | null>(null)\n const [clientSecret, setClientSecret] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(false)\n const hasInitialized = useRef(false)\n\n // Create intent when email is available\n useEffect(() => {\n if (!email || !campaignId || hasInitialized.current) return\n if (!product?.storePriceId) return\n\n hasInitialized.current = true\n setIsLoading(true)\n variableStore.set('payment.loading', true)\n\n const createIntent = async () => {\n try {\n const endpoint = paymentMode === 'setup'\n ? `/campaign/${campaignId}/stripe/setup-intent`\n : `/campaign/${campaignId}/stripe/payment-intent`\n\n const body: Record<string, unknown> = {\n campaignId,\n sessionId: tracker.getSessionId(),\n customerEmail: email,\n priceId: product.storePriceId,\n }\n\n if (validateOnly) body.validateOnly = true\n\n const response = await fetch(`${apiBaseUrl}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n\n const result = await response.json()\n\n if (!result.success) {\n throw new Error(result.error || 'Failed to create intent')\n }\n\n setStripePromise(loadStripe(result.publishableKey))\n setClientSecret(result.clientSecret)\n variableStore.set('user.stripeCustomerId', result.customerId)\n\n tracker.track('checkout.start', {\n productId: product.id,\n priceId: product.stripePriceId || product.storePriceId,\n productName: product.displayName,\n })\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : 'Failed to initialize payment'\n setError(msg)\n variableStore.set('payment.error', msg)\n } finally {\n setIsLoading(false)\n variableStore.set('payment.loading', false)\n }\n }\n\n createIntent()\n }, [email, campaignId, product, paymentMode, validateOnly, tracker, variableStore, apiBaseUrl])\n\n if (isLoading) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>Loading payment form...</div>\n }\n\n if (!email) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#ef4444', fontSize: '14px' }}>Email is required to initialize payment</div>\n }\n\n if (error) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#ef4444', fontSize: '14px' }}>{error}</div>\n }\n\n if (!stripePromise || !clientSecret) {\n return <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>Initializing payment...</div>\n }\n\n const defaultAppearance: Appearance = {\n theme: 'stripe',\n variables: { colorPrimary: '#3b82f6', borderRadius: '8px' },\n }\n\n return (\n <div className={className}>\n <Elements stripe={stripePromise} options={{ clientSecret, appearance: appearance || defaultAppearance }}>\n <InnerPaymentForm\n paymentMode={paymentMode}\n validateOnly={validateOnly}\n onSuccess={onSuccess}\n onError={onError}\n />\n </Elements>\n </div>\n )\n}\n","import { useEffect, useRef, useCallback } from 'react'\nimport { useFunnelContext } from './FunnelProvider'\n\nexport interface PaddleCheckoutProps {\n /** Product ID to checkout (default: currently selected product) */\n productId?: string\n /** Display mode: overlay opens Paddle in a modal, inline renders embedded */\n mode?: 'overlay' | 'inline'\n /** Called on successful checkout */\n onSuccess?: () => void\n /** Called on checkout error */\n onError?: (error: string) => void\n /** Additional CSS class */\n className?: string\n}\n\ndeclare global {\n interface Window {\n Paddle?: {\n Setup: (options: Record<string, unknown>) => void\n Checkout: {\n open: (options: Record<string, unknown>) => void\n }\n }\n }\n}\n\n/**\n * Paddle checkout component.\n * Supports overlay (modal) and inline (embedded) modes.\n */\nexport function PaddleCheckout({\n productId,\n mode = 'overlay',\n onSuccess,\n onError,\n className,\n}: PaddleCheckoutProps) {\n const { variableStore, tracker, products } = useFunnelContext()\n const containerRef = useRef<HTMLDivElement>(null)\n const initializedRef = useRef(false)\n\n // Resolve product\n const product = productId\n ? products.find((p) => p.id === productId)\n : products.find((p) => p.id === (variableStore.get('products.selectedProductId') as string))\n\n const handleCheckoutComplete = useCallback(() => {\n tracker.track('purchase.complete', {\n amount: product?.rawPrice ? product.rawPrice / 100 : 0,\n currency: product?.currencyCode || 'USD',\n })\n onSuccess?.()\n }, [tracker, product, onSuccess])\n\n useEffect(() => {\n if (initializedRef.current || !product?.paddlePriceId) return\n initializedRef.current = true\n\n if (!window.Paddle) {\n onError?.('Paddle.js not loaded. Include the Paddle script in your HTML.')\n return\n }\n\n const email = variableStore.get('user.email') as string || ''\n\n if (mode === 'overlay') {\n window.Paddle.Checkout.open({\n items: [{ priceId: product.paddlePriceId, quantity: 1 }],\n customer: email ? { email } : undefined,\n successCallback: handleCheckoutComplete,\n closeCallback: () => { /* user closed */ },\n })\n } else {\n // Inline mode\n if (containerRef.current) {\n window.Paddle.Checkout.open({\n items: [{ priceId: product.paddlePriceId, quantity: 1 }],\n customer: email ? { email } : undefined,\n settings: {\n displayMode: 'inline',\n frameTarget: containerRef.current.id || 'paddle-checkout',\n frameInitialHeight: 450,\n frameStyle: 'width: 100%; min-width: 312px; background-color: transparent; border: none;',\n },\n successCallback: handleCheckoutComplete,\n })\n }\n }\n\n tracker.track('checkout.start', {\n productId: product.id,\n priceId: product.paddlePriceId,\n productName: product.displayName,\n })\n }, [product, mode, variableStore, tracker, handleCheckoutComplete, onError])\n\n if (!product) {\n return (\n <div className={className} style={{ padding: '20px', textAlign: 'center', color: '#ef4444', fontSize: '14px' }}>\n No product selected\n </div>\n )\n }\n\n if (mode === 'inline') {\n return <div ref={containerRef} id=\"paddle-checkout\" className={className} />\n }\n\n // Overlay mode renders nothing visible\n return null\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as AppFunnelConfig, P as PageDefinition, V as VariableValue, U as UserState, L as LocaleState, T as TranslationState, N as NavigationState, a as ProductsState, b as TrackingState, c as PaymentState, F as FunnelState } from './types-BPNKwDaL.cjs';
2
- export { C as ConditionConfig, d as ConditionGroupConfig, e as FunnelSettings, f as PageConfig, g as PageState, h as PageType, i as ProductConfig, j as ProductsConfig, k as Progress, R as RouteConfig, l as RuntimeProduct, m as VariableConfig, n as VariableType } from './types-BPNKwDaL.cjs';
1
+ import { A as AppFunnelConfig, P as PageDefinition, V as VariableValue, U as UserState, L as LocaleState, T as TranslationState, N as NavigationState, a as ProductsState, b as TrackingState, c as PaymentState, F as FunnelState } from './types-ChorYUCl.cjs';
2
+ export { C as ConditionConfig, d as ConditionGroupConfig, e as FunnelSettings, f as PageConfig, g as PageState, h as PageType, i as ProductConfig, j as ProductsConfig, k as Progress, R as RouteConfig, l as RuntimeProduct, m as VariableConfig, n as VariableType } from './types-ChorYUCl.cjs';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import { Appearance } from '@stripe/stripe-js';
5
5
 
@@ -57,33 +57,66 @@ declare function useVariables(): Record<string, VariableValue>;
57
57
  /**
58
58
  * Read built-in user state (email, name, customerId).
59
59
  *
60
- * For reading/writing arbitrary user fields, use `useUserVariable('fieldName')`.
60
+ * For reading/writing arbitrary user fields, use `useUserProperty('fieldName')`.
61
61
  */
62
62
  declare function useUser(): UserState;
63
63
  /**
64
- * Read/write a user variable by field name.
64
+ * Read/write a user property by field name.
65
65
  * Auto-prefixes with `user.` — no need to define in config.
66
66
  *
67
67
  * ```tsx
68
- * const [dob, setDob] = useUserVariable('dateOfBirth')
69
- * const [gender, setGender] = useUserVariable('gender')
68
+ * const [dob, setDob] = useUserProperty('dateOfBirth')
69
+ * const [gender, setGender] = useUserProperty('gender')
70
70
  * ```
71
71
  */
72
- declare function useUserVariable(field: string): [string, (value: string) => void];
72
+ declare function useUserProperty(field: string): [string, (value: string) => void];
73
73
 
74
74
  /**
75
- * Read URL query parameters.
75
+ * Read/write a single response variable (answers.*).
76
+ *
77
+ * ```tsx
78
+ * const [goal, setGoal] = useResponse<string>('goal')
79
+ * const [interests, setInterests] = useResponse<string[]>('interests')
80
+ * ```
81
+ */
82
+ declare function useResponse<T extends VariableValue>(key: string): [T, (value: T) => void];
83
+ /**
84
+ * Read all response variables as a flat object (without the `answers.` prefix).
85
+ *
86
+ * ```tsx
87
+ * const responses = useResponses()
88
+ * // { goal: 'weight_loss', interests: ['yoga', 'running'] }
89
+ * ```
90
+ */
91
+ declare function useResponses(): Record<string, VariableValue>;
92
+
93
+ /**
94
+ * Read all URL query parameters as a flat object (without the `query.` prefix).
76
95
  *
77
96
  * `query.*` variables are auto-populated from `window.location.search`.
78
97
  * e.g. `?utm_source=google&ref=abc` → `{ utm_source: 'google', ref: 'abc' }`.
79
98
  *
80
99
  * These are read-only from the developer's perspective — they come from the URL.
81
- * Under the hood, they live in the variable store as `query.utm_source`, etc.
82
- *
83
- * Note: The CLI build still emits all `query.*` variables to the published config
84
- * so they can be queried in the analytics database.
85
100
  */
86
101
  declare function useQueryParams(): Record<string, string>;
102
+ /**
103
+ * Read a single query parameter by name.
104
+ *
105
+ * ```tsx
106
+ * const utmSource = useQueryParam('utm_source')
107
+ * ```
108
+ */
109
+ declare function useQueryParam(key: string): string;
110
+
111
+ /**
112
+ * Read/write a single data variable (data.*).
113
+ *
114
+ * ```tsx
115
+ * const [tier, setTier] = useData<string>('selectedPlanTier')
116
+ * const [seen, setSeen] = useData<boolean>('hasSeenOnboarding')
117
+ * ```
118
+ */
119
+ declare function useData<T extends VariableValue>(key: string): [T, (value: T) => void];
87
120
 
88
121
  /**
89
122
  * Get the user's locale from the browser.
@@ -204,4 +237,4 @@ type IntegrationLoader = (config: Record<string, unknown>) => void;
204
237
  */
205
238
  declare function registerIntegration(id: string, loader: IntegrationLoader): void;
206
239
 
207
- export { AppFunnelConfig, FunnelState, type IntegrationConfigs, LocaleState, NavigationState, PaddleCheckout, type PaddleCheckoutProps, PageDefinition, PaymentForm, type PaymentFormProps, PaymentState, ProductsState, TrackingState, TranslationState, UserState, VariableValue, defineConfig, definePage, registerIntegration, useFunnel, useLocale, useNavigation, usePayment, useProducts, useQueryParams, useTracking, useTranslation, useUser, useUserVariable, useVariable, useVariables };
240
+ export { AppFunnelConfig, FunnelState, type IntegrationConfigs, LocaleState, NavigationState, PaddleCheckout, type PaddleCheckoutProps, PageDefinition, PaymentForm, type PaymentFormProps, PaymentState, ProductsState, TrackingState, TranslationState, UserState, VariableValue, defineConfig, definePage, registerIntegration, useData, useFunnel, useLocale, useNavigation, usePayment, useProducts, useQueryParam, useQueryParams, useResponse, useResponses, useTracking, useTranslation, useUser, useUserProperty, useVariable, useVariables };