@funnelsgrove/runtime 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ documented in [`docs/product-specs/funnel-template-runtime.md`](../../docs/produ
|
|
|
37
37
|
|
|
38
38
|
- `config/*`: manifest, theme, font, env, and builder-preview contracts.
|
|
39
39
|
- `runtime/*`: flow, routing, attribution, feature flags, preview bridge, URL attributes, and manifest validation.
|
|
40
|
+
- `runtime/published-runtime-resolution`: running-experiment normalization and immutable offer-set selection from pricing assignments.
|
|
40
41
|
- `services/*`: API client, runtime mode, public env, project env, logger, and funnel state helpers.
|
|
41
42
|
- `components/*`: generic runtime context, subscription handoff/management, editor panel, dev info, and base controls.
|
|
42
43
|
- `content/*` and `steps/types`: shared step content and taxonomy contracts.
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type { FunnelStepChoices } from './runtime/use-step-choices.js';
|
|
|
23
23
|
export * from './runtime/preview-bridge.js';
|
|
24
24
|
export * from './runtime/preview-definition-overrides.js';
|
|
25
25
|
export * from './runtime/offer-set-runtime.js';
|
|
26
|
+
export * from './runtime/published-runtime-resolution.js';
|
|
26
27
|
export * from './runtime/route-resolver.js';
|
|
27
28
|
export * from './runtime/submit-email-capture.js';
|
|
28
29
|
export * from './runtime/subscription-handoff.js';
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export { useStepChoices } from './runtime/use-step-choices.js';
|
|
|
24
24
|
export * from './runtime/preview-bridge.js';
|
|
25
25
|
export * from './runtime/preview-definition-overrides.js';
|
|
26
26
|
export * from './runtime/offer-set-runtime.js';
|
|
27
|
+
export * from './runtime/published-runtime-resolution.js';
|
|
27
28
|
export * from './runtime/route-resolver.js';
|
|
28
29
|
export * from './runtime/submit-email-capture.js';
|
|
29
30
|
export * from './runtime/subscription-handoff.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { FunnelExperimentDefinition, FunnelPricingExperimentDefinition } from '../config/funnel.experiments.types.js';
|
|
2
|
+
import type { FunnelManifestExperiment } from '../config/funnel.manifest.types.js';
|
|
3
|
+
import type { ResolvedFunnelRuntimeConfig } from '../services/funnel-runtime-config.js';
|
|
4
|
+
import type { GeneratedOfferSet } from './offer-set-runtime.js';
|
|
5
|
+
export type ResolvedPublishedExperiments = {
|
|
6
|
+
experiments: readonly FunnelExperimentDefinition[];
|
|
7
|
+
pricingExperiments: readonly FunnelPricingExperimentDefinition[];
|
|
8
|
+
flowExperiments: readonly FunnelManifestExperiment[];
|
|
9
|
+
};
|
|
10
|
+
export type PublishedOfferSetSelection = {
|
|
11
|
+
offerSetId: string;
|
|
12
|
+
offerSet: GeneratedOfferSet | null;
|
|
13
|
+
experimentId: string | null;
|
|
14
|
+
variantKey: string | null;
|
|
15
|
+
};
|
|
16
|
+
export declare const resolvePublishedRuntimeExperiments: (config: ResolvedFunnelRuntimeConfig | null) => ResolvedPublishedExperiments;
|
|
17
|
+
export declare const resolvePublishedOfferSetSelection: ({ offerSets, pricingExperiments, featureFlags, search, defaultOfferSetId, }: {
|
|
18
|
+
offerSets: readonly GeneratedOfferSet[];
|
|
19
|
+
pricingExperiments: readonly FunnelPricingExperimentDefinition[];
|
|
20
|
+
featureFlags: Readonly<Record<string, string>>;
|
|
21
|
+
search?: string;
|
|
22
|
+
defaultOfferSetId?: string;
|
|
23
|
+
}) => PublishedOfferSetSelection;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { toManifestExperiments } from '../config/funnel.experiments.types.js';
|
|
2
|
+
const getPricingExperimentVariants = (experiment) => {
|
|
3
|
+
var _a;
|
|
4
|
+
return ((_a = experiment.variants) === null || _a === void 0 ? void 0 : _a.length)
|
|
5
|
+
? experiment.variants
|
|
6
|
+
: [experiment.control, experiment.variant];
|
|
7
|
+
};
|
|
8
|
+
export const resolvePublishedRuntimeExperiments = (config) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const experiments = (_a = config === null || config === void 0 ? void 0 : config.experiments.filter((experiment) => { var _a; return ((_a = experiment.status) !== null && _a !== void 0 ? _a : 'running') === 'running'; })) !== null && _a !== void 0 ? _a : [];
|
|
11
|
+
return {
|
|
12
|
+
experiments,
|
|
13
|
+
pricingExperiments: experiments.filter((experiment) => experiment.type === 'pricing'),
|
|
14
|
+
flowExperiments: toManifestExperiments(experiments),
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const resolvePublishedOfferSetSelection = ({ offerSets, pricingExperiments, featureFlags, search = '', defaultOfferSetId, }) => {
|
|
18
|
+
var _a, _b, _c, _d, _e;
|
|
19
|
+
const activeOfferSets = offerSets.filter((offerSet) => {
|
|
20
|
+
var _a;
|
|
21
|
+
return (offerSet.isActive !== false && Boolean((_a = offerSet.id) === null || _a === void 0 ? void 0 : _a.trim()));
|
|
22
|
+
});
|
|
23
|
+
const activeOfferSetsById = new Map(activeOfferSets.map((offerSet) => [offerSet.id.trim(), offerSet]));
|
|
24
|
+
const params = new URLSearchParams(search);
|
|
25
|
+
const forcedExperimentId = params.get('mode') === 'test'
|
|
26
|
+
? ((_a = params.get('experiment')) === null || _a === void 0 ? void 0 : _a.trim()) || null
|
|
27
|
+
: null;
|
|
28
|
+
const forcedVariantKey = forcedExperimentId
|
|
29
|
+
? ((_b = params.get('variant')) === null || _b === void 0 ? void 0 : _b.trim()) || null
|
|
30
|
+
: null;
|
|
31
|
+
const resolveExperimentSelection = (experiment, variantKey) => {
|
|
32
|
+
if (!variantKey) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const variant = getPricingExperimentVariants(experiment)
|
|
36
|
+
.find((candidate) => candidate.variantKey === variantKey);
|
|
37
|
+
const offerSet = variant ? activeOfferSetsById.get(variant.offerSetId) : null;
|
|
38
|
+
return variant && offerSet
|
|
39
|
+
? {
|
|
40
|
+
offerSetId: offerSet.id,
|
|
41
|
+
offerSet,
|
|
42
|
+
experimentId: experiment.id,
|
|
43
|
+
variantKey,
|
|
44
|
+
}
|
|
45
|
+
: null;
|
|
46
|
+
};
|
|
47
|
+
if (forcedExperimentId) {
|
|
48
|
+
const forcedExperiment = pricingExperiments.find((experiment) => experiment.id === forcedExperimentId);
|
|
49
|
+
const forcedSelection = forcedExperiment
|
|
50
|
+
? resolveExperimentSelection(forcedExperiment, forcedVariantKey)
|
|
51
|
+
: null;
|
|
52
|
+
if (forcedSelection) {
|
|
53
|
+
return forcedSelection;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const experiment of pricingExperiments) {
|
|
57
|
+
const selection = resolveExperimentSelection(experiment, ((_c = featureFlags[experiment.id]) === null || _c === void 0 ? void 0 : _c.trim()) || null);
|
|
58
|
+
if (selection) {
|
|
59
|
+
return selection;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const defaultOfferSet = defaultOfferSetId
|
|
63
|
+
? activeOfferSetsById.get(defaultOfferSetId.trim())
|
|
64
|
+
: null;
|
|
65
|
+
const offerSet = (_d = defaultOfferSet !== null && defaultOfferSet !== void 0 ? defaultOfferSet : activeOfferSets[0]) !== null && _d !== void 0 ? _d : null;
|
|
66
|
+
return {
|
|
67
|
+
offerSetId: (_e = offerSet === null || offerSet === void 0 ? void 0 : offerSet.id) !== null && _e !== void 0 ? _e : '',
|
|
68
|
+
offerSet,
|
|
69
|
+
experimentId: null,
|
|
70
|
+
variantKey: null,
|
|
71
|
+
};
|
|
72
|
+
};
|