@funnelsgrove/runtime 0.1.13 → 0.1.14
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/components/FunnelContext.d.ts +1 -0
- package/dist/config/env.config.d.ts +4 -0
- package/dist/config/env.config.js +8 -0
- package/dist/config/funnel.experiments.types.d.ts +18 -0
- package/dist/config/funnel.experiments.types.js +23 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/runtime/funnel-attribution.js +1 -0
- package/dist/runtime/use-funnel-flow-controller.js +14 -11
- package/dist/services/project-env.d.ts +4 -0
- package/dist/services/project-env.js +8 -0
- package/package.json +1 -1
|
@@ -33,6 +33,10 @@ export declare const RUNTIME_ENV_KEYS: {
|
|
|
33
33
|
readonly stripeLivePublishableKey: "NEXT_PUBLIC_STRIPE_LIVE_PUBLISHABLE_KEY";
|
|
34
34
|
readonly metaPixelEnabled: "NEXT_PUBLIC_META_PIXEL_ENABLED";
|
|
35
35
|
readonly metaPixelId: "NEXT_PUBLIC_META_PIXEL_ID";
|
|
36
|
+
readonly googleTagEnabled: "NEXT_PUBLIC_GOOGLE_TAG_ENABLED";
|
|
37
|
+
readonly googleAnalyticsId: "NEXT_PUBLIC_GOOGLE_ANALYTICS_ID";
|
|
38
|
+
readonly googleTagManagerId: "NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID";
|
|
39
|
+
readonly googleTagEventTarget: "NEXT_PUBLIC_GOOGLE_TAG_EVENT_TARGET";
|
|
36
40
|
readonly funnelCustomDomain: "FUNNEL_CUSTOM_DOMAIN";
|
|
37
41
|
readonly claimbeeWeeklyPriceId: "NEXT_PUBLIC_CLAIMBEE_WEEKLY_PRICE_ID";
|
|
38
42
|
readonly claimbeeMonthlyPriceId: "NEXT_PUBLIC_CLAIMBEE_MONTHLY_PRICE_ID";
|
|
@@ -44,6 +44,10 @@ export const RUNTIME_ENV_KEYS = {
|
|
|
44
44
|
stripeLivePublishableKey: 'NEXT_PUBLIC_STRIPE_LIVE_PUBLISHABLE_KEY',
|
|
45
45
|
metaPixelEnabled: 'NEXT_PUBLIC_META_PIXEL_ENABLED',
|
|
46
46
|
metaPixelId: 'NEXT_PUBLIC_META_PIXEL_ID',
|
|
47
|
+
googleTagEnabled: 'NEXT_PUBLIC_GOOGLE_TAG_ENABLED',
|
|
48
|
+
googleAnalyticsId: 'NEXT_PUBLIC_GOOGLE_ANALYTICS_ID',
|
|
49
|
+
googleTagManagerId: 'NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID',
|
|
50
|
+
googleTagEventTarget: 'NEXT_PUBLIC_GOOGLE_TAG_EVENT_TARGET',
|
|
47
51
|
funnelCustomDomain: 'FUNNEL_CUSTOM_DOMAIN',
|
|
48
52
|
claimbeeWeeklyPriceId: 'NEXT_PUBLIC_CLAIMBEE_WEEKLY_PRICE_ID',
|
|
49
53
|
claimbeeMonthlyPriceId: 'NEXT_PUBLIC_CLAIMBEE_MONTHLY_PRICE_ID',
|
|
@@ -97,6 +101,10 @@ const RUNTIME_ENV_VALUES = {
|
|
|
97
101
|
NEXT_PUBLIC_STRIPE_LIVE_PUBLISHABLE_KEY: readRuntimeEnv(() => process.env.NEXT_PUBLIC_STRIPE_LIVE_PUBLISHABLE_KEY),
|
|
98
102
|
NEXT_PUBLIC_META_PIXEL_ENABLED: readRuntimeEnv(() => process.env.NEXT_PUBLIC_META_PIXEL_ENABLED),
|
|
99
103
|
NEXT_PUBLIC_META_PIXEL_ID: readRuntimeEnv(() => process.env.NEXT_PUBLIC_META_PIXEL_ID),
|
|
104
|
+
NEXT_PUBLIC_GOOGLE_TAG_ENABLED: readRuntimeEnv(() => process.env.NEXT_PUBLIC_GOOGLE_TAG_ENABLED),
|
|
105
|
+
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: readRuntimeEnv(() => process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID),
|
|
106
|
+
NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID: readRuntimeEnv(() => process.env.NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID),
|
|
107
|
+
NEXT_PUBLIC_GOOGLE_TAG_EVENT_TARGET: readRuntimeEnv(() => process.env.NEXT_PUBLIC_GOOGLE_TAG_EVENT_TARGET),
|
|
100
108
|
NEXT_PUBLIC_CLAIMBEE_WEEKLY_PRICE_ID: readRuntimeEnv(() => process.env.NEXT_PUBLIC_CLAIMBEE_WEEKLY_PRICE_ID),
|
|
101
109
|
NEXT_PUBLIC_CLAIMBEE_MONTHLY_PRICE_ID: readRuntimeEnv(() => process.env.NEXT_PUBLIC_CLAIMBEE_MONTHLY_PRICE_ID),
|
|
102
110
|
NEXT_PUBLIC_CLAIMBEE_YEARLY_PRICE_ID: readRuntimeEnv(() => process.env.NEXT_PUBLIC_CLAIMBEE_YEARLY_PRICE_ID),
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FunnelManifestExperiment } from './funnel.manifest.types.js';
|
|
2
|
+
export type PaywallExperimentDefinition = {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
type: 'paywall';
|
|
6
|
+
launchDate: string;
|
|
7
|
+
control: {
|
|
8
|
+
stepId: string;
|
|
9
|
+
trafficPercent: number;
|
|
10
|
+
};
|
|
11
|
+
variant: {
|
|
12
|
+
stepId: string;
|
|
13
|
+
trafficPercent: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type FunnelExperimentDefinition = PaywallExperimentDefinition;
|
|
17
|
+
export declare const defineFunnelExperiments: <const T extends readonly FunnelExperimentDefinition[]>(experiments: T) => T;
|
|
18
|
+
export declare const toManifestExperiments: (experiments: readonly FunnelExperimentDefinition[]) => FunnelManifestExperiment[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const defineFunnelExperiments = (experiments) => {
|
|
2
|
+
for (const experiment of experiments) {
|
|
3
|
+
const trafficTotal = experiment.control.trafficPercent + experiment.variant.trafficPercent;
|
|
4
|
+
if (trafficTotal !== 100) {
|
|
5
|
+
throw new Error(`Experiment "${experiment.id}" traffic must sum to 100`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
return experiments;
|
|
9
|
+
};
|
|
10
|
+
export const toManifestExperiments = (experiments) => experiments.map((experiment) => ({
|
|
11
|
+
experimentId: experiment.id,
|
|
12
|
+
stepId: experiment.control.stepId,
|
|
13
|
+
variants: [
|
|
14
|
+
{
|
|
15
|
+
variantKey: 'control',
|
|
16
|
+
routeToStepId: experiment.control.stepId,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
variantKey: 'variant_b',
|
|
20
|
+
routeToStepId: experiment.variant.stepId,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
}));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './config/builder-preview.protocol.js';
|
|
2
2
|
export * from './config/env.config.js';
|
|
3
3
|
export * from './config/funnel.manifest.types.js';
|
|
4
|
+
export * from './config/funnel.experiments.types.js';
|
|
4
5
|
export * from './config/funnel-theme.js';
|
|
5
6
|
export * from './config/font-config.js';
|
|
6
7
|
export * from './content/step-content.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './config/builder-preview.protocol.js';
|
|
2
2
|
export * from './config/env.config.js';
|
|
3
3
|
export * from './config/funnel.manifest.types.js';
|
|
4
|
+
export * from './config/funnel.experiments.types.js';
|
|
4
5
|
export * from './config/funnel-theme.js';
|
|
5
6
|
export * from './config/font-config.js';
|
|
6
7
|
export * from './content/step-content.js';
|
|
@@ -363,29 +363,29 @@ export function useFunnelFlowController({ initialStepId, lockToInitialStep = fal
|
|
|
363
363
|
return;
|
|
364
364
|
}
|
|
365
365
|
const prevId = prevStepIdRef.current;
|
|
366
|
-
if (prevId && prevId !==
|
|
366
|
+
if (prevId && prevId !== renderedStepId) {
|
|
367
367
|
recordStepCompletion(prevId);
|
|
368
368
|
}
|
|
369
369
|
const startedAt = new Date().toISOString();
|
|
370
|
-
const stepName = (
|
|
371
|
-
stepStartedAtByIdRef.current[
|
|
370
|
+
const stepName = (renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.name) || (renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.title) || renderedStepId;
|
|
371
|
+
stepStartedAtByIdRef.current[renderedStepId] = startedAt;
|
|
372
372
|
if (!isPreviewRuntime) {
|
|
373
373
|
apiService.trackStepStarted({
|
|
374
374
|
userId: currentUserIdRef.current,
|
|
375
|
-
stepId:
|
|
375
|
+
stepId: renderedStepId,
|
|
376
376
|
stepName,
|
|
377
377
|
startedAt,
|
|
378
378
|
});
|
|
379
|
-
capturePostHogStepEvent('step_started', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, step_id:
|
|
379
|
+
capturePostHogStepEvent('step_started', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, step_id: renderedStepId, step_name: stepName, started_at: startedAt }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
380
380
|
}
|
|
381
381
|
attributesAtStepStart.current = Object.assign({}, attributesRef.current);
|
|
382
|
-
prevStepIdRef.current =
|
|
382
|
+
prevStepIdRef.current = renderedStepId;
|
|
383
383
|
if (isPreviewRuntime ||
|
|
384
|
-
|
|
385
|
-
engagedStepIdsRef.current.has(
|
|
384
|
+
renderedStepId !== defaultStepId ||
|
|
385
|
+
engagedStepIdsRef.current.has(renderedStepId)) {
|
|
386
386
|
return;
|
|
387
387
|
}
|
|
388
|
-
const engagedStepId =
|
|
388
|
+
const engagedStepId = renderedStepId;
|
|
389
389
|
const engagedStartedAt = startedAt;
|
|
390
390
|
const engagedStepName = stepName;
|
|
391
391
|
const timer = window.setTimeout(() => {
|
|
@@ -411,12 +411,13 @@ export function useFunnelFlowController({ initialStepId, lockToInitialStep = fal
|
|
|
411
411
|
return () => window.clearTimeout(timer);
|
|
412
412
|
}, [
|
|
413
413
|
activeStepId,
|
|
414
|
-
activeStepMeta === null || activeStepMeta === void 0 ? void 0 : activeStepMeta.name,
|
|
415
|
-
activeStepMeta === null || activeStepMeta === void 0 ? void 0 : activeStepMeta.title,
|
|
416
414
|
defaultStepId,
|
|
417
415
|
isPreviewRuntime,
|
|
418
416
|
recordStepCompletion,
|
|
419
417
|
renderSuspended,
|
|
418
|
+
renderedStepId,
|
|
419
|
+
renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.name,
|
|
420
|
+
renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.title,
|
|
420
421
|
safeActiveStepId,
|
|
421
422
|
]);
|
|
422
423
|
useEffect(() => {
|
|
@@ -532,6 +533,7 @@ export function useFunnelFlowController({ initialStepId, lockToInitialStep = fal
|
|
|
532
533
|
}, [editorVariantOverrides, postHogReady]);
|
|
533
534
|
const contextValue = useMemo(() => ({
|
|
534
535
|
activeStepId: safeActiveStepId,
|
|
536
|
+
featureFlags: postHogFeatureFlags,
|
|
535
537
|
isBuilder: isPreviewRuntime,
|
|
536
538
|
goToStep: goToStepFromContext,
|
|
537
539
|
goNext,
|
|
@@ -558,6 +560,7 @@ export function useFunnelFlowController({ initialStepId, lockToInitialStep = fal
|
|
|
558
560
|
goNext,
|
|
559
561
|
goToStepFromContext,
|
|
560
562
|
isPreviewRuntime,
|
|
563
|
+
postHogFeatureFlags,
|
|
561
564
|
resolveRenderableStepId,
|
|
562
565
|
safeActiveStepId,
|
|
563
566
|
setAnswer,
|
|
@@ -33,6 +33,10 @@ export declare const PROJECT_ENV_STANDARD_KEYS: {
|
|
|
33
33
|
readonly metaPixelId: "NEXT_PUBLIC_META_PIXEL_ID";
|
|
34
34
|
readonly metaConversionsAccessToken: "META_CONVERSIONS_ACCESS_TOKEN";
|
|
35
35
|
readonly metaTestEventCode: "META_TEST_EVENT_CODE";
|
|
36
|
+
readonly googleTagEnabled: "NEXT_PUBLIC_GOOGLE_TAG_ENABLED";
|
|
37
|
+
readonly googleAnalyticsId: "NEXT_PUBLIC_GOOGLE_ANALYTICS_ID";
|
|
38
|
+
readonly googleTagManagerId: "NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID";
|
|
39
|
+
readonly googleTagEventTarget: "NEXT_PUBLIC_GOOGLE_TAG_EVENT_TARGET";
|
|
36
40
|
};
|
|
37
41
|
export type ProjectEnvStandardKey = keyof typeof PROJECT_ENV_STANDARD_KEYS;
|
|
38
42
|
export type ProjectEnvStandardValues = Record<ProjectEnvStandardKey, string>;
|
|
@@ -33,6 +33,10 @@ export const PROJECT_ENV_STANDARD_KEYS = {
|
|
|
33
33
|
metaPixelId: 'NEXT_PUBLIC_META_PIXEL_ID',
|
|
34
34
|
metaConversionsAccessToken: 'META_CONVERSIONS_ACCESS_TOKEN',
|
|
35
35
|
metaTestEventCode: 'META_TEST_EVENT_CODE',
|
|
36
|
+
googleTagEnabled: 'NEXT_PUBLIC_GOOGLE_TAG_ENABLED',
|
|
37
|
+
googleAnalyticsId: 'NEXT_PUBLIC_GOOGLE_ANALYTICS_ID',
|
|
38
|
+
googleTagManagerId: 'NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID',
|
|
39
|
+
googleTagEventTarget: 'NEXT_PUBLIC_GOOGLE_TAG_EVENT_TARGET',
|
|
36
40
|
};
|
|
37
41
|
export const normalizeProjectEnvValue = (value) => {
|
|
38
42
|
return (value === null || value === void 0 ? void 0 : value.trim()) || '';
|
|
@@ -100,6 +104,10 @@ const buildProjectStandardValues = (envMap) => {
|
|
|
100
104
|
metaPixelId: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.metaPixelId),
|
|
101
105
|
metaConversionsAccessToken: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.metaConversionsAccessToken),
|
|
102
106
|
metaTestEventCode: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.metaTestEventCode),
|
|
107
|
+
googleTagEnabled: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.googleTagEnabled),
|
|
108
|
+
googleAnalyticsId: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.googleAnalyticsId),
|
|
109
|
+
googleTagManagerId: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.googleTagManagerId),
|
|
110
|
+
googleTagEventTarget: getProjectEnvValue(envMap, PROJECT_ENV_STANDARD_KEYS.googleTagEventTarget),
|
|
103
111
|
};
|
|
104
112
|
};
|
|
105
113
|
export const parseProjectEnvVariables = (variables) => {
|