@funnelsgrove/runtime 0.1.29 → 0.1.31
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/RuntimeDevInfoBox.js +15 -1
- package/dist/runtime/posthog-flags.d.ts +2 -0
- package/dist/runtime/posthog-flags.js +19 -0
- package/dist/runtime/use-funnel-flow-controller.js +11 -3
- package/dist/services/api.service.d.ts +3 -0
- package/dist/services/api.service.js +2 -0
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
4
|
import { clearPaywallStateValue } from '../services/funnel-state.service.js';
|
|
5
5
|
import { RUNTIME_PUBLIC_ENV_KEYS, runtimePublicConfig, } from '../services/public-env.js';
|
|
6
|
+
import { isPreviewFrameRuntimeSearch } from '../services/preview-frame.service.js';
|
|
6
7
|
const normalizeDisplayValue = (value) => {
|
|
7
8
|
if (value === null || typeof value === 'undefined' || value === '') {
|
|
8
9
|
return '(empty)';
|
|
@@ -19,6 +20,19 @@ const runtimePublicConfigEntries = () => {
|
|
|
19
20
|
const canUseDom = () => {
|
|
20
21
|
return typeof window !== 'undefined';
|
|
21
22
|
};
|
|
23
|
+
const isRuntimeDevInfoHidden = () => {
|
|
24
|
+
if (!canUseDom()) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const search = window.location.search;
|
|
29
|
+
return (new URLSearchParams(search).get('hideRuntimeDevTools') === '1' ||
|
|
30
|
+
isPreviewFrameRuntimeSearch(search));
|
|
31
|
+
}
|
|
32
|
+
catch (_a) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
22
36
|
export const copyRuntimeDevInfoValue = async (value) => {
|
|
23
37
|
var _a, _b;
|
|
24
38
|
if (!value || value === '(empty)') {
|
|
@@ -65,7 +79,7 @@ export function RuntimeDevInfoBox({ runtimeMode, user, onSwitchToLiveMode, confi
|
|
|
65
79
|
const [copiedKey, setCopiedKey] = useState(null);
|
|
66
80
|
const [resetDone, setResetDone] = useState(false);
|
|
67
81
|
const configItems = useMemo(() => [...configValues, ...runtimePublicConfigEntries()], [configValues]);
|
|
68
|
-
if (runtimeMode !== 'test') {
|
|
82
|
+
if (runtimeMode !== 'test' || isRuntimeDevInfoHidden()) {
|
|
69
83
|
return null;
|
|
70
84
|
}
|
|
71
85
|
const markCopied = (key) => {
|
|
@@ -4,6 +4,8 @@ type BootstrapConfig = {
|
|
|
4
4
|
apiKey: string;
|
|
5
5
|
apiHost: string;
|
|
6
6
|
distinctId: string;
|
|
7
|
+
projectId?: string;
|
|
8
|
+
funnelId?: string;
|
|
7
9
|
};
|
|
8
10
|
export declare const bootstrapPostHog: (config: BootstrapConfig) => Promise<void>;
|
|
9
11
|
export declare const isPostHogReady: () => boolean;
|
|
@@ -2,6 +2,19 @@ import posthog from 'posthog-js';
|
|
|
2
2
|
let initialized = false;
|
|
3
3
|
let readyPromise = null;
|
|
4
4
|
export const POSTHOG_FEATURE_FLAG_READY_TIMEOUT_MS = 2500;
|
|
5
|
+
const buildFlagScopeProperties = (config) => {
|
|
6
|
+
var _a, _b;
|
|
7
|
+
const properties = {};
|
|
8
|
+
const projectId = (_a = config.projectId) === null || _a === void 0 ? void 0 : _a.trim();
|
|
9
|
+
const funnelId = (_b = config.funnelId) === null || _b === void 0 ? void 0 : _b.trim();
|
|
10
|
+
if (projectId) {
|
|
11
|
+
properties.project_id = projectId;
|
|
12
|
+
}
|
|
13
|
+
if (funnelId) {
|
|
14
|
+
properties.funnel_id = funnelId;
|
|
15
|
+
}
|
|
16
|
+
return properties;
|
|
17
|
+
};
|
|
5
18
|
export const bootstrapPostHog = (config) => {
|
|
6
19
|
if (readyPromise) {
|
|
7
20
|
return readyPromise;
|
|
@@ -27,13 +40,19 @@ export const bootstrapPostHog = (config) => {
|
|
|
27
40
|
api_host: config.apiHost,
|
|
28
41
|
persistence: 'localStorage+cookie',
|
|
29
42
|
person_profiles: 'identified_only',
|
|
43
|
+
advanced_disable_feature_flags_on_first_load: true,
|
|
30
44
|
bootstrap: { distinctID: config.distinctId },
|
|
31
45
|
loaded: () => {
|
|
46
|
+
const scopeProperties = buildFlagScopeProperties(config);
|
|
47
|
+
if (Object.keys(scopeProperties).length > 0) {
|
|
48
|
+
posthog.setPersonPropertiesForFlags(scopeProperties, false);
|
|
49
|
+
}
|
|
32
50
|
let unsubscribe = null;
|
|
33
51
|
unsubscribe = posthog.onFeatureFlags(() => {
|
|
34
52
|
unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
|
|
35
53
|
markReady();
|
|
36
54
|
});
|
|
55
|
+
posthog.reloadFeatureFlags();
|
|
37
56
|
},
|
|
38
57
|
});
|
|
39
58
|
});
|
|
@@ -275,6 +275,8 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
275
275
|
apiKey: POSTHOG_PROJECT_API_KEY,
|
|
276
276
|
apiHost: POSTHOG_API_HOST,
|
|
277
277
|
distinctId: localUserId,
|
|
278
|
+
projectId: PROJECT_ID,
|
|
279
|
+
funnelId: FUNNEL_ID,
|
|
278
280
|
})
|
|
279
281
|
.then(() => setPostHogReady(true))
|
|
280
282
|
.catch((error) => {
|
|
@@ -352,6 +354,7 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
352
354
|
completedAt: new Date().toISOString(),
|
|
353
355
|
choices,
|
|
354
356
|
};
|
|
357
|
+
const stepType = meta.type;
|
|
355
358
|
const startedAt = stepStartedAtByIdRef.current[meta.id] || record.completedAt;
|
|
356
359
|
const durationMs = Math.max(0, new Date(record.completedAt).getTime() - new Date(startedAt).getTime());
|
|
357
360
|
dispatchWindowCustomEvent('funnel:step-completed', record);
|
|
@@ -360,11 +363,12 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
360
363
|
userId: currentUserIdRef.current,
|
|
361
364
|
stepId: record.stepId,
|
|
362
365
|
stepName: record.stepName,
|
|
366
|
+
stepType,
|
|
363
367
|
startedAt,
|
|
364
368
|
endedAt: record.completedAt,
|
|
365
369
|
selected: record.choices,
|
|
366
370
|
});
|
|
367
|
-
capturePostHogStepEvent('step_completed', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: record.stepId, step_name: record.stepName, started_at: startedAt, ended_at: record.completedAt, duration_ms: Number.isFinite(durationMs) ? durationMs : undefined, selected: record.choices }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
371
|
+
capturePostHogStepEvent('step_completed', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: record.stepId, step_name: record.stepName, step_type: stepType, started_at: startedAt, ended_at: record.completedAt, duration_ms: Number.isFinite(durationMs) ? durationMs : undefined, selected: record.choices }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
368
372
|
}
|
|
369
373
|
setUser((prev) => {
|
|
370
374
|
var _a, _b;
|
|
@@ -410,15 +414,17 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
410
414
|
}
|
|
411
415
|
const startedAt = new Date().toISOString();
|
|
412
416
|
const stepName = (renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.name) || (renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.title) || renderedStepId;
|
|
417
|
+
const stepType = renderedStepMeta === null || renderedStepMeta === void 0 ? void 0 : renderedStepMeta.type;
|
|
413
418
|
stepStartedAtByIdRef.current[renderedStepId] = startedAt;
|
|
414
419
|
if (!isPreviewRuntime) {
|
|
415
420
|
apiService.trackStepStarted({
|
|
416
421
|
userId: currentUserIdRef.current,
|
|
417
422
|
stepId: renderedStepId,
|
|
418
423
|
stepName,
|
|
424
|
+
stepType,
|
|
419
425
|
startedAt,
|
|
420
426
|
});
|
|
421
|
-
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, environment: runtimeMode, step_id: renderedStepId, step_name: stepName, started_at: startedAt }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
427
|
+
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, environment: runtimeMode, step_id: renderedStepId, step_name: stepName, step_type: stepType, started_at: startedAt }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
422
428
|
if (!firstStepViewedTrackedRef.current && safeActiveStepId === defaultStepId) {
|
|
423
429
|
firstStepViewedTrackedRef.current = true;
|
|
424
430
|
(_a = analytics === null || analytics === void 0 ? void 0 : analytics.trackFirstStepViewed) === null || _a === void 0 ? void 0 : _a.call(analytics, {
|
|
@@ -439,6 +445,7 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
439
445
|
const engagedStepId = renderedStepId;
|
|
440
446
|
const engagedStartedAt = startedAt;
|
|
441
447
|
const engagedStepName = stepName;
|
|
448
|
+
const engagedStepType = stepType;
|
|
442
449
|
const timer = window.setTimeout(() => {
|
|
443
450
|
if (prevStepIdRef.current !== engagedStepId || engagedStepIdsRef.current.has(engagedStepId)) {
|
|
444
451
|
return;
|
|
@@ -450,6 +457,7 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
450
457
|
eventType: 'step_engaged',
|
|
451
458
|
stepId: engagedStepId,
|
|
452
459
|
stepName: engagedStepName,
|
|
460
|
+
stepType: engagedStepType,
|
|
453
461
|
startedAt: engagedStartedAt,
|
|
454
462
|
endedAt: engagedAt,
|
|
455
463
|
metadata: {
|
|
@@ -457,7 +465,7 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
457
465
|
engagementThresholdMs: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS,
|
|
458
466
|
},
|
|
459
467
|
});
|
|
460
|
-
capturePostHogStepEvent('step_engaged', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: engagedStepId, step_name: engagedStepName, started_at: engagedStartedAt, ended_at: engagedAt, duration_ms: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS, engagement_threshold_ms: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
468
|
+
capturePostHogStepEvent('step_engaged', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: engagedStepId, step_name: engagedStepName, step_type: engagedStepType, started_at: engagedStartedAt, ended_at: engagedAt, duration_ms: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS, engagement_threshold_ms: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
461
469
|
}, FIRST_STEP_ENGAGEMENT_THRESHOLD_MS);
|
|
462
470
|
return () => window.clearTimeout(timer);
|
|
463
471
|
}, [
|
|
@@ -16,6 +16,7 @@ export type FunnelEvent = {
|
|
|
16
16
|
eventType: string;
|
|
17
17
|
stepId?: string;
|
|
18
18
|
stepName?: string;
|
|
19
|
+
stepType?: string;
|
|
19
20
|
startedAt?: string;
|
|
20
21
|
endedAt?: string;
|
|
21
22
|
selected?: Record<string, unknown>;
|
|
@@ -25,6 +26,7 @@ export type StepCompletionEvent = {
|
|
|
25
26
|
userId: string;
|
|
26
27
|
stepId: string;
|
|
27
28
|
stepName: string;
|
|
29
|
+
stepType?: string;
|
|
28
30
|
startedAt: string;
|
|
29
31
|
endedAt: string;
|
|
30
32
|
selected: Record<string, unknown>;
|
|
@@ -104,6 +106,7 @@ declare class ApiService {
|
|
|
104
106
|
userId: string;
|
|
105
107
|
stepId: string;
|
|
106
108
|
stepName: string;
|
|
109
|
+
stepType?: string;
|
|
107
110
|
startedAt: string;
|
|
108
111
|
}): void;
|
|
109
112
|
trackStepCompleted(event: StepCompletionEvent): void;
|
|
@@ -493,6 +493,7 @@ class ApiService {
|
|
|
493
493
|
eventType: 'step_start',
|
|
494
494
|
stepId: input.stepId,
|
|
495
495
|
stepName: input.stepName,
|
|
496
|
+
stepType: input.stepType,
|
|
496
497
|
startedAt: input.startedAt,
|
|
497
498
|
});
|
|
498
499
|
}
|
|
@@ -502,6 +503,7 @@ class ApiService {
|
|
|
502
503
|
eventType: 'step_end',
|
|
503
504
|
stepId: event.stepId,
|
|
504
505
|
stepName: event.stepName,
|
|
506
|
+
stepType: event.stepType,
|
|
505
507
|
startedAt: event.startedAt,
|
|
506
508
|
endedAt: event.endedAt,
|
|
507
509
|
selected: event.selected,
|