@ninetailed/experience.js-plugin-preview 4.1.0-beta.0 → 4.1.0-beta.2

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/index.cjs CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var omit = require('lodash/omit');
5
6
  var experience_js = require('@ninetailed/experience.js');
6
- var experience_jsPluginAnalytics = require('@ninetailed/experience.js-plugin-analytics');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var react = require('react');
9
9
  var uuid = require('uuid');
10
+ var unionBy = require('lodash/unionBy');
11
+
12
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
13
 
11
14
  function _interopNamespace(e) {
12
15
  if (e && e.__esModule) return e;
@@ -26,6 +29,9 @@ function _interopNamespace(e) {
26
29
  return Object.freeze(n);
27
30
  }
28
31
 
32
+ var omit__default = /*#__PURE__*/_interopDefaultLegacy(omit);
33
+ var unionBy__default = /*#__PURE__*/_interopDefaultLegacy(unionBy);
34
+
29
35
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
30
36
 
31
37
  var check = function (it) {
@@ -2432,9 +2438,99 @@ var addToUnscopables$2 = function (key) {
2432
2438
  ArrayPrototype[UNSCOPABLES][key] = true;
2433
2439
  };
2434
2440
 
2441
+ var $$3 = _export;
2442
+ var $includes = arrayIncludes.includes;
2435
2443
  var fails$3 = fails$f;
2444
+ var addToUnscopables$1 = addToUnscopables$2;
2445
+
2446
+ // FF99+ bug
2447
+ var BROKEN_ON_SPARSE = fails$3(function () {
2448
+ return !Array(1).includes();
2449
+ });
2450
+
2451
+ // `Array.prototype.includes` method
2452
+ // https://tc39.es/ecma262/#sec-array.prototype.includes
2453
+ $$3({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE }, {
2454
+ includes: function includes(el /* , fromIndex = 0 */) {
2455
+ return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
2456
+ }
2457
+ });
2458
+
2459
+ // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2460
+ addToUnscopables$1('includes');
2461
+
2462
+ var isObject$1 = isObject$9;
2463
+ var classof$1 = classofRaw$2;
2464
+ var wellKnownSymbol$4 = wellKnownSymbol$g;
2465
+
2466
+ var MATCH$1 = wellKnownSymbol$4('match');
2467
+
2468
+ // `IsRegExp` abstract operation
2469
+ // https://tc39.es/ecma262/#sec-isregexp
2470
+ var isRegexp = function (it) {
2471
+ var isRegExp;
2472
+ return isObject$1(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classof$1(it) == 'RegExp');
2473
+ };
2474
+
2475
+ var isRegExp = isRegexp;
2476
+
2477
+ var $TypeError$1 = TypeError;
2478
+
2479
+ var notARegexp = function (it) {
2480
+ if (isRegExp(it)) {
2481
+ throw $TypeError$1("The method doesn't accept regular expressions");
2482
+ } return it;
2483
+ };
2484
+
2485
+ var classof = classof$4;
2486
+
2487
+ var $String = String;
2488
+
2489
+ var toString$1 = function (argument) {
2490
+ if (classof(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');
2491
+ return $String(argument);
2492
+ };
2493
+
2494
+ var wellKnownSymbol$3 = wellKnownSymbol$g;
2495
+
2496
+ var MATCH = wellKnownSymbol$3('match');
2436
2497
 
2437
- var correctPrototypeGetter = !fails$3(function () {
2498
+ var correctIsRegexpLogic = function (METHOD_NAME) {
2499
+ var regexp = /./;
2500
+ try {
2501
+ '/./'[METHOD_NAME](regexp);
2502
+ } catch (error1) {
2503
+ try {
2504
+ regexp[MATCH] = false;
2505
+ return '/./'[METHOD_NAME](regexp);
2506
+ } catch (error2) { /* empty */ }
2507
+ } return false;
2508
+ };
2509
+
2510
+ var $$2 = _export;
2511
+ var uncurryThis = functionUncurryThis;
2512
+ var notARegExp = notARegexp;
2513
+ var requireObjectCoercible = requireObjectCoercible$3;
2514
+ var toString = toString$1;
2515
+ var correctIsRegExpLogic = correctIsRegexpLogic;
2516
+
2517
+ var stringIndexOf = uncurryThis(''.indexOf);
2518
+
2519
+ // `String.prototype.includes` method
2520
+ // https://tc39.es/ecma262/#sec-string.prototype.includes
2521
+ $$2({ target: 'String', proto: true, forced: !correctIsRegExpLogic('includes') }, {
2522
+ includes: function includes(searchString /* , position = 0 */) {
2523
+ return !!~stringIndexOf(
2524
+ toString(requireObjectCoercible(this)),
2525
+ toString(notARegExp(searchString)),
2526
+ arguments.length > 1 ? arguments[1] : undefined
2527
+ );
2528
+ }
2529
+ });
2530
+
2531
+ var fails$2 = fails$f;
2532
+
2533
+ var correctPrototypeGetter = !fails$2(function () {
2438
2534
  function F() { /* empty */ }
2439
2535
  F.prototype.constructor = null;
2440
2536
  // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
@@ -2463,14 +2559,14 @@ var objectGetPrototypeOf = CORRECT_PROTOTYPE_GETTER ? $Object.getPrototypeOf : f
2463
2559
  } return object instanceof $Object ? ObjectPrototype : null;
2464
2560
  };
2465
2561
 
2466
- var fails$2 = fails$f;
2562
+ var fails$1 = fails$f;
2467
2563
  var isCallable$1 = isCallable$k;
2468
- var isObject$1 = isObject$9;
2564
+ var isObject = isObject$9;
2469
2565
  var getPrototypeOf$1 = objectGetPrototypeOf;
2470
2566
  var defineBuiltIn$1 = defineBuiltIn$5;
2471
- var wellKnownSymbol$4 = wellKnownSymbol$g;
2567
+ var wellKnownSymbol$2 = wellKnownSymbol$g;
2472
2568
 
2473
- var ITERATOR$2 = wellKnownSymbol$4('iterator');
2569
+ var ITERATOR$2 = wellKnownSymbol$2('iterator');
2474
2570
  var BUGGY_SAFARI_ITERATORS$1 = false;
2475
2571
 
2476
2572
  // `%IteratorPrototype%` object
@@ -2488,7 +2584,7 @@ if ([].keys) {
2488
2584
  }
2489
2585
  }
2490
2586
 
2491
- var NEW_ITERATOR_PROTOTYPE = !isObject$1(IteratorPrototype$2) || fails$2(function () {
2587
+ var NEW_ITERATOR_PROTOTYPE = !isObject(IteratorPrototype$2) || fails$1(function () {
2492
2588
  var test = {};
2493
2589
  // FF44- legacy iterators case
2494
2590
  return IteratorPrototype$2[ITERATOR$2].call(test) !== test;
@@ -2525,7 +2621,7 @@ var iteratorCreateConstructor = function (IteratorConstructor, NAME, next, ENUME
2525
2621
  return IteratorConstructor;
2526
2622
  };
2527
2623
 
2528
- var $$3 = _export;
2624
+ var $$1 = _export;
2529
2625
  var call = functionCall;
2530
2626
  var FunctionName = functionName;
2531
2627
  var isCallable = isCallable$k;
@@ -2535,7 +2631,7 @@ var setPrototypeOf = objectSetPrototypeOf;
2535
2631
  var setToStringTag = setToStringTag$3;
2536
2632
  var createNonEnumerableProperty$1 = createNonEnumerableProperty$4;
2537
2633
  var defineBuiltIn = defineBuiltIn$5;
2538
- var wellKnownSymbol$3 = wellKnownSymbol$g;
2634
+ var wellKnownSymbol$1 = wellKnownSymbol$g;
2539
2635
  var Iterators$1 = iterators;
2540
2636
  var IteratorsCore = iteratorsCore;
2541
2637
 
@@ -2543,7 +2639,7 @@ var PROPER_FUNCTION_NAME = FunctionName.PROPER;
2543
2639
  var CONFIGURABLE_FUNCTION_NAME = FunctionName.CONFIGURABLE;
2544
2640
  var IteratorPrototype = IteratorsCore.IteratorPrototype;
2545
2641
  var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;
2546
- var ITERATOR$1 = wellKnownSymbol$3('iterator');
2642
+ var ITERATOR$1 = wellKnownSymbol$1('iterator');
2547
2643
  var KEYS = 'keys';
2548
2644
  var VALUES = 'values';
2549
2645
  var ENTRIES = 'entries';
@@ -2610,7 +2706,7 @@ var iteratorDefine = function (Iterable, NAME, IteratorConstructor, next, DEFAUL
2610
2706
  if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
2611
2707
  defineBuiltIn(IterablePrototype, KEY, methods[KEY]);
2612
2708
  }
2613
- } else $$3({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
2709
+ } else $$1({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
2614
2710
  }
2615
2711
 
2616
2712
  // define iterator
@@ -2629,7 +2725,7 @@ var createIterResultObject$1 = function (value, done) {
2629
2725
  };
2630
2726
 
2631
2727
  var toIndexedObject = toIndexedObject$5;
2632
- var addToUnscopables$1 = addToUnscopables$2;
2728
+ var addToUnscopables = addToUnscopables$2;
2633
2729
  var Iterators = iterators;
2634
2730
  var InternalStateModule = internalState;
2635
2731
  var defineProperty = objectDefineProperty.f;
@@ -2680,9 +2776,9 @@ var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind)
2680
2776
  var values = Iterators.Arguments = Iterators.Array;
2681
2777
 
2682
2778
  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2683
- addToUnscopables$1('keys');
2684
- addToUnscopables$1('values');
2685
- addToUnscopables$1('entries');
2779
+ addToUnscopables('keys');
2780
+ addToUnscopables('values');
2781
+ addToUnscopables('entries');
2686
2782
 
2687
2783
  // V8 ~ Chrome 45- bug
2688
2784
  if (DESCRIPTORS && values.name !== 'values') try {
@@ -2738,10 +2834,10 @@ var DOMIterables = domIterables;
2738
2834
  var DOMTokenListPrototype = domTokenListPrototype;
2739
2835
  var ArrayIteratorMethods = es_array_iterator;
2740
2836
  var createNonEnumerableProperty = createNonEnumerableProperty$4;
2741
- var wellKnownSymbol$2 = wellKnownSymbol$g;
2837
+ var wellKnownSymbol = wellKnownSymbol$g;
2742
2838
 
2743
- var ITERATOR = wellKnownSymbol$2('iterator');
2744
- var TO_STRING_TAG = wellKnownSymbol$2('toStringTag');
2839
+ var ITERATOR = wellKnownSymbol('iterator');
2840
+ var TO_STRING_TAG = wellKnownSymbol('toStringTag');
2745
2841
  var ArrayValues = ArrayIteratorMethods.values;
2746
2842
 
2747
2843
  var handlePrototype = function (CollectionPrototype, COLLECTION_NAME) {
@@ -2772,96 +2868,6 @@ for (var COLLECTION_NAME in DOMIterables) {
2772
2868
 
2773
2869
  handlePrototype(DOMTokenListPrototype, 'DOMTokenList');
2774
2870
 
2775
- var $$2 = _export;
2776
- var $includes = arrayIncludes.includes;
2777
- var fails$1 = fails$f;
2778
- var addToUnscopables = addToUnscopables$2;
2779
-
2780
- // FF99+ bug
2781
- var BROKEN_ON_SPARSE = fails$1(function () {
2782
- return !Array(1).includes();
2783
- });
2784
-
2785
- // `Array.prototype.includes` method
2786
- // https://tc39.es/ecma262/#sec-array.prototype.includes
2787
- $$2({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE }, {
2788
- includes: function includes(el /* , fromIndex = 0 */) {
2789
- return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
2790
- }
2791
- });
2792
-
2793
- // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2794
- addToUnscopables('includes');
2795
-
2796
- var isObject = isObject$9;
2797
- var classof$1 = classofRaw$2;
2798
- var wellKnownSymbol$1 = wellKnownSymbol$g;
2799
-
2800
- var MATCH$1 = wellKnownSymbol$1('match');
2801
-
2802
- // `IsRegExp` abstract operation
2803
- // https://tc39.es/ecma262/#sec-isregexp
2804
- var isRegexp = function (it) {
2805
- var isRegExp;
2806
- return isObject(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classof$1(it) == 'RegExp');
2807
- };
2808
-
2809
- var isRegExp = isRegexp;
2810
-
2811
- var $TypeError$1 = TypeError;
2812
-
2813
- var notARegexp = function (it) {
2814
- if (isRegExp(it)) {
2815
- throw $TypeError$1("The method doesn't accept regular expressions");
2816
- } return it;
2817
- };
2818
-
2819
- var classof = classof$4;
2820
-
2821
- var $String = String;
2822
-
2823
- var toString$1 = function (argument) {
2824
- if (classof(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');
2825
- return $String(argument);
2826
- };
2827
-
2828
- var wellKnownSymbol = wellKnownSymbol$g;
2829
-
2830
- var MATCH = wellKnownSymbol('match');
2831
-
2832
- var correctIsRegexpLogic = function (METHOD_NAME) {
2833
- var regexp = /./;
2834
- try {
2835
- '/./'[METHOD_NAME](regexp);
2836
- } catch (error1) {
2837
- try {
2838
- regexp[MATCH] = false;
2839
- return '/./'[METHOD_NAME](regexp);
2840
- } catch (error2) { /* empty */ }
2841
- } return false;
2842
- };
2843
-
2844
- var $$1 = _export;
2845
- var uncurryThis = functionUncurryThis;
2846
- var notARegExp = notARegexp;
2847
- var requireObjectCoercible = requireObjectCoercible$3;
2848
- var toString = toString$1;
2849
- var correctIsRegExpLogic = correctIsRegexpLogic;
2850
-
2851
- var stringIndexOf = uncurryThis(''.indexOf);
2852
-
2853
- // `String.prototype.includes` method
2854
- // https://tc39.es/ecma262/#sec-string.prototype.includes
2855
- $$1({ target: 'String', proto: true, forced: !correctIsRegExpLogic('includes') }, {
2856
- includes: function includes(searchString /* , position = 0 */) {
2857
- return !!~stringIndexOf(
2858
- toString(requireObjectCoercible(this)),
2859
- toString(notARegExp(searchString)),
2860
- arguments.length > 1 ? arguments[1] : undefined
2861
- );
2862
- }
2863
- });
2864
-
2865
2871
  var aCallable = aCallable$8;
2866
2872
  var toObject = toObject$4;
2867
2873
  var IndexedObject = indexedObject;
@@ -3041,32 +3047,36 @@ const PreviewRenderPlugin = ctx => {
3041
3047
  };
3042
3048
  }, [id]);
3043
3049
  react.useEffect(() => {
3044
- const overWrittenExperienceIds = Object.keys(pluginApi.experienceVariantIndexOverwrites);
3045
- const overWrittenExperience = experiences.find(experience => {
3046
- return overWrittenExperienceIds.includes(experience.id);
3050
+ const experienceIds = Object.keys(pluginApi.experienceVariantIndexes);
3051
+ const experience = experiences.find(experience => {
3052
+ const hasActiveAudience = pluginApi.activeAudiences.some(activeAudienceId => {
3053
+ var _a;
3054
+ return ((_a = experience.audience) === null || _a === void 0 ? void 0 : _a.id) === activeAudienceId;
3055
+ });
3056
+ return hasActiveAudience && experienceIds.includes(experience.id);
3047
3057
  });
3048
- if (!overWrittenExperience) {
3049
- setComponentProps({});
3058
+ if (!experience) {
3059
+ setComponentProps(baseline);
3050
3060
  return;
3051
3061
  }
3052
- const baselineComponent = overWrittenExperience.components.find(component => component.baseline.id === baseline.id);
3062
+ const baselineComponent = experience.components.find(component => component.baseline.id === baseline.id);
3053
3063
  if (!baselineComponent) {
3054
- setComponentProps({});
3064
+ setComponentProps(baseline);
3055
3065
  return;
3056
3066
  }
3057
3067
  const allVariants = [baseline, ...baselineComponent.variants];
3058
- const variantIndex = pluginApi.experienceVariantIndexOverwrites[overWrittenExperience.id];
3068
+ const variantIndex = pluginApi.experienceVariantIndexes[experience.id];
3059
3069
  if (allVariants.length <= variantIndex) {
3060
- setComponentProps({});
3070
+ setComponentProps(baseline);
3061
3071
  return;
3062
3072
  }
3063
3073
  const variant = allVariants[variantIndex];
3064
3074
  if (!variant) {
3065
- setComponentProps({});
3075
+ setComponentProps(baseline);
3066
3076
  return;
3067
3077
  }
3068
- setComponentProps(Object.assign({}, variant));
3069
- }, [experiences, baseline, setComponentProps, pluginApi.experienceVariantIndexOverwrites]);
3078
+ setComponentProps(variant);
3079
+ }, [experiences, baseline, setComponentProps, pluginApi.experienceVariantIndexes, pluginApi.activeAudiences]);
3070
3080
  return jsxRuntime.jsx(jsxRuntime.Fragment, {
3071
3081
  children: children
3072
3082
  });
@@ -3092,19 +3102,21 @@ class PreviewRenderPluginContext {
3092
3102
  }
3093
3103
 
3094
3104
  var _a;
3095
- class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlugin {
3105
+ class NinetailedPreviewPlugin extends experience_js.NinetailedPlugin {
3096
3106
  constructor(options) {
3097
3107
  super();
3098
3108
  this.options = options;
3099
3109
  this.name = 'ninetailed:preview' + Math.random();
3100
3110
  this.isOpen = false;
3101
3111
  this.experiences = [];
3112
+ this.audienceDefinitions = [];
3102
3113
  this.audienceOverwrites = {};
3103
3114
  this.experienceVariantIndexOverwrites = {};
3104
3115
  this.profile = null;
3105
3116
  this.container = null;
3106
3117
  this.bridge = null;
3107
3118
  this.renderPluginContext = new PreviewRenderPluginContext(this.pluginApi);
3119
+ this.onChangeEmitter = new experience_js.OnChangeEmitter();
3108
3120
  this.initialize = () => __awaiter(this, void 0, void 0, function* () {
3109
3121
  var _b;
3110
3122
  if (typeof window !== 'undefined') {
@@ -3139,8 +3151,56 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3139
3151
  this.onProfileChange(payload.profile);
3140
3152
  }
3141
3153
  };
3154
+ this.getExperienceSelectionMiddleware = ({
3155
+ baseline,
3156
+ experiences
3157
+ }) => {
3158
+ return () => {
3159
+ const experienceIds = Object.keys(this.pluginApi.experienceVariantIndexes);
3160
+ const experience = experiences.find(experience => {
3161
+ const hasActiveAudience = this.pluginApi.activeAudiences.some(activeAudienceId => {
3162
+ var _b;
3163
+ return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === activeAudienceId;
3164
+ });
3165
+ return hasActiveAudience && experienceIds.includes(experience.id);
3166
+ });
3167
+ if (!experience) {
3168
+ return {
3169
+ experience: null,
3170
+ variant: null
3171
+ };
3172
+ }
3173
+ const baselineComponent = experience.components.find(component => component.baseline.id === baseline.id);
3174
+ if (!baselineComponent) {
3175
+ return {
3176
+ experience,
3177
+ variant: null
3178
+ };
3179
+ }
3180
+ const allVariants = [baseline, ...baselineComponent.variants];
3181
+ const variantIndex = this.pluginApi.experienceVariantIndexes[experience.id];
3182
+ if (allVariants.length <= variantIndex) {
3183
+ return {
3184
+ experience,
3185
+ variant: null
3186
+ };
3187
+ }
3188
+ const variant = allVariants[variantIndex];
3189
+ if (!variant) {
3190
+ return {
3191
+ experience,
3192
+ variant: null
3193
+ };
3194
+ }
3195
+ return {
3196
+ experience,
3197
+ variant
3198
+ };
3199
+ };
3200
+ };
3142
3201
  this.onChange = () => {
3143
3202
  var _b;
3203
+ console.debug('Ninetailed Preview Plugin onChange pluginApi:', this.pluginApi);
3144
3204
  Object.assign({}, window.ninetailed, {
3145
3205
  plugins: Object.assign(Object.assign({}, (_b = window.ninetailed) === null || _b === void 0 ? void 0 : _b.plugins), {
3146
3206
  preview: this.windowApi
@@ -3149,15 +3209,14 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3149
3209
  this.bridge.updateProps({
3150
3210
  props: this.pluginApi
3151
3211
  });
3152
- if (this.renderPluginContext.setPluginApi) {
3153
- this.renderPluginContext.setPluginApi(this.pluginApi);
3154
- }
3212
+ this.onChangeEmitter.invokeListeners();
3155
3213
  };
3156
3214
  this.onProfileChange = profile => {
3157
3215
  this.profile = profile;
3158
3216
  this.onChange();
3159
3217
  };
3160
3218
  this.experiences = options.experiences || [];
3219
+ this.audienceDefinitions = options.audiences || [];
3161
3220
  this.renderPluginComponent = PreviewRenderPlugin(this.renderPluginContext);
3162
3221
  }
3163
3222
  open() {
@@ -3186,16 +3245,17 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3186
3245
  console.log(`You cannot activate an unkown audience (id: ${id}).`);
3187
3246
  return;
3188
3247
  }
3189
- // When a audience is activated, they should show their natural state
3190
- this.experiences.filter(experience => {
3191
- var _b;
3192
- return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === id;
3193
- }).forEach(experience => {
3194
- this.resetExperience(experience.id);
3195
- });
3196
3248
  this.audienceOverwrites = Object.assign(Object.assign({}, this.audienceOverwrites), {
3197
3249
  [id]: true
3198
3250
  });
3251
+ this.experienceVariantIndexOverwrites = Object.assign(Object.assign({}, this.experienceVariantIndexOverwrites), this.experiences.filter(experience => {
3252
+ var _b;
3253
+ return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === id;
3254
+ }).map(experience => experience.id).reduce((acc, curr) => {
3255
+ return Object.assign(Object.assign({}, acc), {
3256
+ [curr]: this.experienceVariantIndexes[curr] || 0
3257
+ });
3258
+ }, {}));
3199
3259
  this.onChange();
3200
3260
  }
3201
3261
  deactivateAudience(id) {
@@ -3203,16 +3263,19 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3203
3263
  console.log(`You cannot deactivate an unkown audience (id: ${id}). How did you get it in the first place?`);
3204
3264
  return;
3205
3265
  }
3206
- // When a audience is deactivated, the normal state will be that the experience goes into the control
3207
- this.experiences.filter(experience => {
3266
+ // // When a audience is deactivated, the normal state will be that the experience goes into the control
3267
+ // this.experiences
3268
+ // .filter((experience) => experience.audience?.id === id)
3269
+ // .forEach((experience) => {
3270
+ // this.setExperienceVariant({
3271
+ // experienceId: experience.id,
3272
+ // variantIndex: 0,
3273
+ // });
3274
+ // });
3275
+ this.experienceVariantIndexOverwrites = omit__default["default"](this.experienceVariantIndexOverwrites, this.experiences.filter(experience => {
3208
3276
  var _b;
3209
3277
  return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === id;
3210
- }).forEach(experience => {
3211
- this.setExperienceVariant({
3212
- experienceId: experience.id,
3213
- variantIndex: 0
3214
- });
3215
- });
3278
+ }).map(experience => experience.id));
3216
3279
  this.audienceOverwrites = Object.assign(Object.assign({}, this.audienceOverwrites), {
3217
3280
  [id]: false
3218
3281
  });
@@ -3284,6 +3347,7 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3284
3347
  apiAudiences: ((_b = this.profile) === null || _b === void 0 ? void 0 : _b.audiences) || [],
3285
3348
  audienceOverwrites: this.audienceOverwrites,
3286
3349
  activeAudiences: this.activeAudiences,
3350
+ audienceDefinitions: this.audienceDefinitions,
3287
3351
  setExperienceVariant: this.setExperienceVariant.bind(this),
3288
3352
  resetExperience: this.resetExperience.bind(this),
3289
3353
  experienceVariantIndexes: Object.assign(Object.assign({}, this.experienceVariantIndexes), this.experienceVariantIndexOverwrites),
@@ -3311,7 +3375,8 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3311
3375
  return this.potentialAudiences.some(audience => audience.id === id);
3312
3376
  }
3313
3377
  get potentialAudiences() {
3314
- return this.experiences.map(experience => experience.audience).filter(audience => !!audience);
3378
+ const audiencesFromExperiences = this.experiences.map(experience => experience.audience).filter(audience => !!audience);
3379
+ return unionBy__default["default"](this.audienceDefinitions, audiencesFromExperiences, 'id');
3315
3380
  }
3316
3381
  get activeAudiences() {
3317
3382
  var _b;
@@ -3325,7 +3390,9 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3325
3390
  return {};
3326
3391
  }
3327
3392
  const experiments = this.experiences.filter(experience => experience.type === 'nt_experiment');
3328
- const activeExperiments = experience_js.selectActiveExperiments(experiments, profile);
3393
+ const activeExperiments = experience_js.selectActiveExperiments(experiments, Object.assign(Object.assign({}, profile), {
3394
+ audiences: this.activeAudiences
3395
+ }));
3329
3396
  const eligibleExperiences = experience_js.selectEligibleExperiences({
3330
3397
  experiences: this.experiences,
3331
3398
  activeExperiments
@@ -3333,12 +3400,16 @@ class NinetailedPreviewPlugin extends experience_jsPluginAnalytics.NinetailedPlu
3333
3400
  const matchedExperiences = eligibleExperiences.filter(experience => experience_js.isExperienceMatch({
3334
3401
  experience,
3335
3402
  activeExperiments,
3336
- profile
3403
+ profile: Object.assign(Object.assign({}, profile), {
3404
+ audiences: this.activeAudiences
3405
+ })
3337
3406
  }));
3338
3407
  return matchedExperiences.reduce((acc, experience) => {
3339
3408
  const distribution = experience_js.selectDistribution({
3340
3409
  experience,
3341
- profile
3410
+ profile: Object.assign(Object.assign({}, profile), {
3411
+ audiences: this.activeAudiences
3412
+ })
3342
3413
  });
3343
3414
  return Object.assign(Object.assign({}, acc), {
3344
3415
  [experience.id]: distribution.index
package/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { selectActiveExperiments, selectEligibleExperiences, isExperienceMatch, selectDistribution, PROFILE_CHANGE } from '@ninetailed/experience.js';
2
- import { NinetailedPlugin } from '@ninetailed/experience.js-plugin-analytics';
1
+ import omit from 'lodash/omit';
2
+ import { NinetailedPlugin, OnChangeEmitter, selectActiveExperiments, selectEligibleExperiences, isExperienceMatch, selectDistribution, PROFILE_CHANGE } from '@ninetailed/experience.js';
3
3
  import { jsx, Fragment } from 'react/jsx-runtime';
4
4
  import { useState, useRef, useEffect } from 'react';
5
5
  import { v4 } from 'uuid';
6
+ import unionBy from 'lodash/unionBy';
6
7
 
7
8
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
8
9
 
@@ -2410,9 +2411,99 @@ var addToUnscopables$2 = function (key) {
2410
2411
  ArrayPrototype[UNSCOPABLES][key] = true;
2411
2412
  };
2412
2413
 
2414
+ var $$3 = _export;
2415
+ var $includes = arrayIncludes.includes;
2413
2416
  var fails$3 = fails$f;
2417
+ var addToUnscopables$1 = addToUnscopables$2;
2418
+
2419
+ // FF99+ bug
2420
+ var BROKEN_ON_SPARSE = fails$3(function () {
2421
+ return !Array(1).includes();
2422
+ });
2423
+
2424
+ // `Array.prototype.includes` method
2425
+ // https://tc39.es/ecma262/#sec-array.prototype.includes
2426
+ $$3({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE }, {
2427
+ includes: function includes(el /* , fromIndex = 0 */) {
2428
+ return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
2429
+ }
2430
+ });
2431
+
2432
+ // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2433
+ addToUnscopables$1('includes');
2434
+
2435
+ var isObject$1 = isObject$9;
2436
+ var classof$1 = classofRaw$2;
2437
+ var wellKnownSymbol$4 = wellKnownSymbol$g;
2414
2438
 
2415
- var correctPrototypeGetter = !fails$3(function () {
2439
+ var MATCH$1 = wellKnownSymbol$4('match');
2440
+
2441
+ // `IsRegExp` abstract operation
2442
+ // https://tc39.es/ecma262/#sec-isregexp
2443
+ var isRegexp = function (it) {
2444
+ var isRegExp;
2445
+ return isObject$1(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classof$1(it) == 'RegExp');
2446
+ };
2447
+
2448
+ var isRegExp = isRegexp;
2449
+
2450
+ var $TypeError$1 = TypeError;
2451
+
2452
+ var notARegexp = function (it) {
2453
+ if (isRegExp(it)) {
2454
+ throw $TypeError$1("The method doesn't accept regular expressions");
2455
+ } return it;
2456
+ };
2457
+
2458
+ var classof = classof$4;
2459
+
2460
+ var $String = String;
2461
+
2462
+ var toString$1 = function (argument) {
2463
+ if (classof(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');
2464
+ return $String(argument);
2465
+ };
2466
+
2467
+ var wellKnownSymbol$3 = wellKnownSymbol$g;
2468
+
2469
+ var MATCH = wellKnownSymbol$3('match');
2470
+
2471
+ var correctIsRegexpLogic = function (METHOD_NAME) {
2472
+ var regexp = /./;
2473
+ try {
2474
+ '/./'[METHOD_NAME](regexp);
2475
+ } catch (error1) {
2476
+ try {
2477
+ regexp[MATCH] = false;
2478
+ return '/./'[METHOD_NAME](regexp);
2479
+ } catch (error2) { /* empty */ }
2480
+ } return false;
2481
+ };
2482
+
2483
+ var $$2 = _export;
2484
+ var uncurryThis = functionUncurryThis;
2485
+ var notARegExp = notARegexp;
2486
+ var requireObjectCoercible = requireObjectCoercible$3;
2487
+ var toString = toString$1;
2488
+ var correctIsRegExpLogic = correctIsRegexpLogic;
2489
+
2490
+ var stringIndexOf = uncurryThis(''.indexOf);
2491
+
2492
+ // `String.prototype.includes` method
2493
+ // https://tc39.es/ecma262/#sec-string.prototype.includes
2494
+ $$2({ target: 'String', proto: true, forced: !correctIsRegExpLogic('includes') }, {
2495
+ includes: function includes(searchString /* , position = 0 */) {
2496
+ return !!~stringIndexOf(
2497
+ toString(requireObjectCoercible(this)),
2498
+ toString(notARegExp(searchString)),
2499
+ arguments.length > 1 ? arguments[1] : undefined
2500
+ );
2501
+ }
2502
+ });
2503
+
2504
+ var fails$2 = fails$f;
2505
+
2506
+ var correctPrototypeGetter = !fails$2(function () {
2416
2507
  function F() { /* empty */ }
2417
2508
  F.prototype.constructor = null;
2418
2509
  // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
@@ -2441,14 +2532,14 @@ var objectGetPrototypeOf = CORRECT_PROTOTYPE_GETTER ? $Object.getPrototypeOf : f
2441
2532
  } return object instanceof $Object ? ObjectPrototype : null;
2442
2533
  };
2443
2534
 
2444
- var fails$2 = fails$f;
2535
+ var fails$1 = fails$f;
2445
2536
  var isCallable$1 = isCallable$k;
2446
- var isObject$1 = isObject$9;
2537
+ var isObject = isObject$9;
2447
2538
  var getPrototypeOf$1 = objectGetPrototypeOf;
2448
2539
  var defineBuiltIn$1 = defineBuiltIn$5;
2449
- var wellKnownSymbol$4 = wellKnownSymbol$g;
2540
+ var wellKnownSymbol$2 = wellKnownSymbol$g;
2450
2541
 
2451
- var ITERATOR$2 = wellKnownSymbol$4('iterator');
2542
+ var ITERATOR$2 = wellKnownSymbol$2('iterator');
2452
2543
  var BUGGY_SAFARI_ITERATORS$1 = false;
2453
2544
 
2454
2545
  // `%IteratorPrototype%` object
@@ -2466,7 +2557,7 @@ if ([].keys) {
2466
2557
  }
2467
2558
  }
2468
2559
 
2469
- var NEW_ITERATOR_PROTOTYPE = !isObject$1(IteratorPrototype$2) || fails$2(function () {
2560
+ var NEW_ITERATOR_PROTOTYPE = !isObject(IteratorPrototype$2) || fails$1(function () {
2470
2561
  var test = {};
2471
2562
  // FF44- legacy iterators case
2472
2563
  return IteratorPrototype$2[ITERATOR$2].call(test) !== test;
@@ -2503,7 +2594,7 @@ var iteratorCreateConstructor = function (IteratorConstructor, NAME, next, ENUME
2503
2594
  return IteratorConstructor;
2504
2595
  };
2505
2596
 
2506
- var $$3 = _export;
2597
+ var $$1 = _export;
2507
2598
  var call = functionCall;
2508
2599
  var FunctionName = functionName;
2509
2600
  var isCallable = isCallable$k;
@@ -2513,7 +2604,7 @@ var setPrototypeOf = objectSetPrototypeOf;
2513
2604
  var setToStringTag = setToStringTag$3;
2514
2605
  var createNonEnumerableProperty$1 = createNonEnumerableProperty$4;
2515
2606
  var defineBuiltIn = defineBuiltIn$5;
2516
- var wellKnownSymbol$3 = wellKnownSymbol$g;
2607
+ var wellKnownSymbol$1 = wellKnownSymbol$g;
2517
2608
  var Iterators$1 = iterators;
2518
2609
  var IteratorsCore = iteratorsCore;
2519
2610
 
@@ -2521,7 +2612,7 @@ var PROPER_FUNCTION_NAME = FunctionName.PROPER;
2521
2612
  var CONFIGURABLE_FUNCTION_NAME = FunctionName.CONFIGURABLE;
2522
2613
  var IteratorPrototype = IteratorsCore.IteratorPrototype;
2523
2614
  var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;
2524
- var ITERATOR$1 = wellKnownSymbol$3('iterator');
2615
+ var ITERATOR$1 = wellKnownSymbol$1('iterator');
2525
2616
  var KEYS = 'keys';
2526
2617
  var VALUES = 'values';
2527
2618
  var ENTRIES = 'entries';
@@ -2588,7 +2679,7 @@ var iteratorDefine = function (Iterable, NAME, IteratorConstructor, next, DEFAUL
2588
2679
  if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
2589
2680
  defineBuiltIn(IterablePrototype, KEY, methods[KEY]);
2590
2681
  }
2591
- } else $$3({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
2682
+ } else $$1({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
2592
2683
  }
2593
2684
 
2594
2685
  // define iterator
@@ -2607,7 +2698,7 @@ var createIterResultObject$1 = function (value, done) {
2607
2698
  };
2608
2699
 
2609
2700
  var toIndexedObject = toIndexedObject$5;
2610
- var addToUnscopables$1 = addToUnscopables$2;
2701
+ var addToUnscopables = addToUnscopables$2;
2611
2702
  var Iterators = iterators;
2612
2703
  var InternalStateModule = internalState;
2613
2704
  var defineProperty = objectDefineProperty.f;
@@ -2658,9 +2749,9 @@ var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind)
2658
2749
  var values = Iterators.Arguments = Iterators.Array;
2659
2750
 
2660
2751
  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2661
- addToUnscopables$1('keys');
2662
- addToUnscopables$1('values');
2663
- addToUnscopables$1('entries');
2752
+ addToUnscopables('keys');
2753
+ addToUnscopables('values');
2754
+ addToUnscopables('entries');
2664
2755
 
2665
2756
  // V8 ~ Chrome 45- bug
2666
2757
  if (DESCRIPTORS && values.name !== 'values') try {
@@ -2716,10 +2807,10 @@ var DOMIterables = domIterables;
2716
2807
  var DOMTokenListPrototype = domTokenListPrototype;
2717
2808
  var ArrayIteratorMethods = es_array_iterator;
2718
2809
  var createNonEnumerableProperty = createNonEnumerableProperty$4;
2719
- var wellKnownSymbol$2 = wellKnownSymbol$g;
2810
+ var wellKnownSymbol = wellKnownSymbol$g;
2720
2811
 
2721
- var ITERATOR = wellKnownSymbol$2('iterator');
2722
- var TO_STRING_TAG = wellKnownSymbol$2('toStringTag');
2812
+ var ITERATOR = wellKnownSymbol('iterator');
2813
+ var TO_STRING_TAG = wellKnownSymbol('toStringTag');
2723
2814
  var ArrayValues = ArrayIteratorMethods.values;
2724
2815
 
2725
2816
  var handlePrototype = function (CollectionPrototype, COLLECTION_NAME) {
@@ -2750,96 +2841,6 @@ for (var COLLECTION_NAME in DOMIterables) {
2750
2841
 
2751
2842
  handlePrototype(DOMTokenListPrototype, 'DOMTokenList');
2752
2843
 
2753
- var $$2 = _export;
2754
- var $includes = arrayIncludes.includes;
2755
- var fails$1 = fails$f;
2756
- var addToUnscopables = addToUnscopables$2;
2757
-
2758
- // FF99+ bug
2759
- var BROKEN_ON_SPARSE = fails$1(function () {
2760
- return !Array(1).includes();
2761
- });
2762
-
2763
- // `Array.prototype.includes` method
2764
- // https://tc39.es/ecma262/#sec-array.prototype.includes
2765
- $$2({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE }, {
2766
- includes: function includes(el /* , fromIndex = 0 */) {
2767
- return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
2768
- }
2769
- });
2770
-
2771
- // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
2772
- addToUnscopables('includes');
2773
-
2774
- var isObject = isObject$9;
2775
- var classof$1 = classofRaw$2;
2776
- var wellKnownSymbol$1 = wellKnownSymbol$g;
2777
-
2778
- var MATCH$1 = wellKnownSymbol$1('match');
2779
-
2780
- // `IsRegExp` abstract operation
2781
- // https://tc39.es/ecma262/#sec-isregexp
2782
- var isRegexp = function (it) {
2783
- var isRegExp;
2784
- return isObject(it) && ((isRegExp = it[MATCH$1]) !== undefined ? !!isRegExp : classof$1(it) == 'RegExp');
2785
- };
2786
-
2787
- var isRegExp = isRegexp;
2788
-
2789
- var $TypeError$1 = TypeError;
2790
-
2791
- var notARegexp = function (it) {
2792
- if (isRegExp(it)) {
2793
- throw $TypeError$1("The method doesn't accept regular expressions");
2794
- } return it;
2795
- };
2796
-
2797
- var classof = classof$4;
2798
-
2799
- var $String = String;
2800
-
2801
- var toString$1 = function (argument) {
2802
- if (classof(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');
2803
- return $String(argument);
2804
- };
2805
-
2806
- var wellKnownSymbol = wellKnownSymbol$g;
2807
-
2808
- var MATCH = wellKnownSymbol('match');
2809
-
2810
- var correctIsRegexpLogic = function (METHOD_NAME) {
2811
- var regexp = /./;
2812
- try {
2813
- '/./'[METHOD_NAME](regexp);
2814
- } catch (error1) {
2815
- try {
2816
- regexp[MATCH] = false;
2817
- return '/./'[METHOD_NAME](regexp);
2818
- } catch (error2) { /* empty */ }
2819
- } return false;
2820
- };
2821
-
2822
- var $$1 = _export;
2823
- var uncurryThis = functionUncurryThis;
2824
- var notARegExp = notARegexp;
2825
- var requireObjectCoercible = requireObjectCoercible$3;
2826
- var toString = toString$1;
2827
- var correctIsRegExpLogic = correctIsRegexpLogic;
2828
-
2829
- var stringIndexOf = uncurryThis(''.indexOf);
2830
-
2831
- // `String.prototype.includes` method
2832
- // https://tc39.es/ecma262/#sec-string.prototype.includes
2833
- $$1({ target: 'String', proto: true, forced: !correctIsRegExpLogic('includes') }, {
2834
- includes: function includes(searchString /* , position = 0 */) {
2835
- return !!~stringIndexOf(
2836
- toString(requireObjectCoercible(this)),
2837
- toString(notARegExp(searchString)),
2838
- arguments.length > 1 ? arguments[1] : undefined
2839
- );
2840
- }
2841
- });
2842
-
2843
2844
  var aCallable = aCallable$8;
2844
2845
  var toObject = toObject$4;
2845
2846
  var IndexedObject = indexedObject;
@@ -3019,32 +3020,36 @@ const PreviewRenderPlugin = ctx => {
3019
3020
  };
3020
3021
  }, [id]);
3021
3022
  useEffect(() => {
3022
- const overWrittenExperienceIds = Object.keys(pluginApi.experienceVariantIndexOverwrites);
3023
- const overWrittenExperience = experiences.find(experience => {
3024
- return overWrittenExperienceIds.includes(experience.id);
3023
+ const experienceIds = Object.keys(pluginApi.experienceVariantIndexes);
3024
+ const experience = experiences.find(experience => {
3025
+ const hasActiveAudience = pluginApi.activeAudiences.some(activeAudienceId => {
3026
+ var _a;
3027
+ return ((_a = experience.audience) === null || _a === void 0 ? void 0 : _a.id) === activeAudienceId;
3028
+ });
3029
+ return hasActiveAudience && experienceIds.includes(experience.id);
3025
3030
  });
3026
- if (!overWrittenExperience) {
3027
- setComponentProps({});
3031
+ if (!experience) {
3032
+ setComponentProps(baseline);
3028
3033
  return;
3029
3034
  }
3030
- const baselineComponent = overWrittenExperience.components.find(component => component.baseline.id === baseline.id);
3035
+ const baselineComponent = experience.components.find(component => component.baseline.id === baseline.id);
3031
3036
  if (!baselineComponent) {
3032
- setComponentProps({});
3037
+ setComponentProps(baseline);
3033
3038
  return;
3034
3039
  }
3035
3040
  const allVariants = [baseline, ...baselineComponent.variants];
3036
- const variantIndex = pluginApi.experienceVariantIndexOverwrites[overWrittenExperience.id];
3041
+ const variantIndex = pluginApi.experienceVariantIndexes[experience.id];
3037
3042
  if (allVariants.length <= variantIndex) {
3038
- setComponentProps({});
3043
+ setComponentProps(baseline);
3039
3044
  return;
3040
3045
  }
3041
3046
  const variant = allVariants[variantIndex];
3042
3047
  if (!variant) {
3043
- setComponentProps({});
3048
+ setComponentProps(baseline);
3044
3049
  return;
3045
3050
  }
3046
- setComponentProps(Object.assign({}, variant));
3047
- }, [experiences, baseline, setComponentProps, pluginApi.experienceVariantIndexOverwrites]);
3051
+ setComponentProps(variant);
3052
+ }, [experiences, baseline, setComponentProps, pluginApi.experienceVariantIndexes, pluginApi.activeAudiences]);
3048
3053
  return jsx(Fragment, {
3049
3054
  children: children
3050
3055
  });
@@ -3077,12 +3082,14 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3077
3082
  this.name = 'ninetailed:preview' + Math.random();
3078
3083
  this.isOpen = false;
3079
3084
  this.experiences = [];
3085
+ this.audienceDefinitions = [];
3080
3086
  this.audienceOverwrites = {};
3081
3087
  this.experienceVariantIndexOverwrites = {};
3082
3088
  this.profile = null;
3083
3089
  this.container = null;
3084
3090
  this.bridge = null;
3085
3091
  this.renderPluginContext = new PreviewRenderPluginContext(this.pluginApi);
3092
+ this.onChangeEmitter = new OnChangeEmitter();
3086
3093
  this.initialize = () => __awaiter(this, void 0, void 0, function* () {
3087
3094
  var _b;
3088
3095
  if (typeof window !== 'undefined') {
@@ -3117,8 +3124,56 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3117
3124
  this.onProfileChange(payload.profile);
3118
3125
  }
3119
3126
  };
3127
+ this.getExperienceSelectionMiddleware = ({
3128
+ baseline,
3129
+ experiences
3130
+ }) => {
3131
+ return () => {
3132
+ const experienceIds = Object.keys(this.pluginApi.experienceVariantIndexes);
3133
+ const experience = experiences.find(experience => {
3134
+ const hasActiveAudience = this.pluginApi.activeAudiences.some(activeAudienceId => {
3135
+ var _b;
3136
+ return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === activeAudienceId;
3137
+ });
3138
+ return hasActiveAudience && experienceIds.includes(experience.id);
3139
+ });
3140
+ if (!experience) {
3141
+ return {
3142
+ experience: null,
3143
+ variant: null
3144
+ };
3145
+ }
3146
+ const baselineComponent = experience.components.find(component => component.baseline.id === baseline.id);
3147
+ if (!baselineComponent) {
3148
+ return {
3149
+ experience,
3150
+ variant: null
3151
+ };
3152
+ }
3153
+ const allVariants = [baseline, ...baselineComponent.variants];
3154
+ const variantIndex = this.pluginApi.experienceVariantIndexes[experience.id];
3155
+ if (allVariants.length <= variantIndex) {
3156
+ return {
3157
+ experience,
3158
+ variant: null
3159
+ };
3160
+ }
3161
+ const variant = allVariants[variantIndex];
3162
+ if (!variant) {
3163
+ return {
3164
+ experience,
3165
+ variant: null
3166
+ };
3167
+ }
3168
+ return {
3169
+ experience,
3170
+ variant
3171
+ };
3172
+ };
3173
+ };
3120
3174
  this.onChange = () => {
3121
3175
  var _b;
3176
+ console.debug('Ninetailed Preview Plugin onChange pluginApi:', this.pluginApi);
3122
3177
  Object.assign({}, window.ninetailed, {
3123
3178
  plugins: Object.assign(Object.assign({}, (_b = window.ninetailed) === null || _b === void 0 ? void 0 : _b.plugins), {
3124
3179
  preview: this.windowApi
@@ -3127,15 +3182,14 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3127
3182
  this.bridge.updateProps({
3128
3183
  props: this.pluginApi
3129
3184
  });
3130
- if (this.renderPluginContext.setPluginApi) {
3131
- this.renderPluginContext.setPluginApi(this.pluginApi);
3132
- }
3185
+ this.onChangeEmitter.invokeListeners();
3133
3186
  };
3134
3187
  this.onProfileChange = profile => {
3135
3188
  this.profile = profile;
3136
3189
  this.onChange();
3137
3190
  };
3138
3191
  this.experiences = options.experiences || [];
3192
+ this.audienceDefinitions = options.audiences || [];
3139
3193
  this.renderPluginComponent = PreviewRenderPlugin(this.renderPluginContext);
3140
3194
  }
3141
3195
  open() {
@@ -3164,16 +3218,17 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3164
3218
  console.log(`You cannot activate an unkown audience (id: ${id}).`);
3165
3219
  return;
3166
3220
  }
3167
- // When a audience is activated, they should show their natural state
3168
- this.experiences.filter(experience => {
3169
- var _b;
3170
- return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === id;
3171
- }).forEach(experience => {
3172
- this.resetExperience(experience.id);
3173
- });
3174
3221
  this.audienceOverwrites = Object.assign(Object.assign({}, this.audienceOverwrites), {
3175
3222
  [id]: true
3176
3223
  });
3224
+ this.experienceVariantIndexOverwrites = Object.assign(Object.assign({}, this.experienceVariantIndexOverwrites), this.experiences.filter(experience => {
3225
+ var _b;
3226
+ return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === id;
3227
+ }).map(experience => experience.id).reduce((acc, curr) => {
3228
+ return Object.assign(Object.assign({}, acc), {
3229
+ [curr]: this.experienceVariantIndexes[curr] || 0
3230
+ });
3231
+ }, {}));
3177
3232
  this.onChange();
3178
3233
  }
3179
3234
  deactivateAudience(id) {
@@ -3181,16 +3236,19 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3181
3236
  console.log(`You cannot deactivate an unkown audience (id: ${id}). How did you get it in the first place?`);
3182
3237
  return;
3183
3238
  }
3184
- // When a audience is deactivated, the normal state will be that the experience goes into the control
3185
- this.experiences.filter(experience => {
3239
+ // // When a audience is deactivated, the normal state will be that the experience goes into the control
3240
+ // this.experiences
3241
+ // .filter((experience) => experience.audience?.id === id)
3242
+ // .forEach((experience) => {
3243
+ // this.setExperienceVariant({
3244
+ // experienceId: experience.id,
3245
+ // variantIndex: 0,
3246
+ // });
3247
+ // });
3248
+ this.experienceVariantIndexOverwrites = omit(this.experienceVariantIndexOverwrites, this.experiences.filter(experience => {
3186
3249
  var _b;
3187
3250
  return ((_b = experience.audience) === null || _b === void 0 ? void 0 : _b.id) === id;
3188
- }).forEach(experience => {
3189
- this.setExperienceVariant({
3190
- experienceId: experience.id,
3191
- variantIndex: 0
3192
- });
3193
- });
3251
+ }).map(experience => experience.id));
3194
3252
  this.audienceOverwrites = Object.assign(Object.assign({}, this.audienceOverwrites), {
3195
3253
  [id]: false
3196
3254
  });
@@ -3262,6 +3320,7 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3262
3320
  apiAudiences: ((_b = this.profile) === null || _b === void 0 ? void 0 : _b.audiences) || [],
3263
3321
  audienceOverwrites: this.audienceOverwrites,
3264
3322
  activeAudiences: this.activeAudiences,
3323
+ audienceDefinitions: this.audienceDefinitions,
3265
3324
  setExperienceVariant: this.setExperienceVariant.bind(this),
3266
3325
  resetExperience: this.resetExperience.bind(this),
3267
3326
  experienceVariantIndexes: Object.assign(Object.assign({}, this.experienceVariantIndexes), this.experienceVariantIndexOverwrites),
@@ -3289,7 +3348,8 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3289
3348
  return this.potentialAudiences.some(audience => audience.id === id);
3290
3349
  }
3291
3350
  get potentialAudiences() {
3292
- return this.experiences.map(experience => experience.audience).filter(audience => !!audience);
3351
+ const audiencesFromExperiences = this.experiences.map(experience => experience.audience).filter(audience => !!audience);
3352
+ return unionBy(this.audienceDefinitions, audiencesFromExperiences, 'id');
3293
3353
  }
3294
3354
  get activeAudiences() {
3295
3355
  var _b;
@@ -3303,7 +3363,9 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3303
3363
  return {};
3304
3364
  }
3305
3365
  const experiments = this.experiences.filter(experience => experience.type === 'nt_experiment');
3306
- const activeExperiments = selectActiveExperiments(experiments, profile);
3366
+ const activeExperiments = selectActiveExperiments(experiments, Object.assign(Object.assign({}, profile), {
3367
+ audiences: this.activeAudiences
3368
+ }));
3307
3369
  const eligibleExperiences = selectEligibleExperiences({
3308
3370
  experiences: this.experiences,
3309
3371
  activeExperiments
@@ -3311,12 +3373,16 @@ class NinetailedPreviewPlugin extends NinetailedPlugin {
3311
3373
  const matchedExperiences = eligibleExperiences.filter(experience => isExperienceMatch({
3312
3374
  experience,
3313
3375
  activeExperiments,
3314
- profile
3376
+ profile: Object.assign(Object.assign({}, profile), {
3377
+ audiences: this.activeAudiences
3378
+ })
3315
3379
  }));
3316
3380
  return matchedExperiences.reduce((acc, experience) => {
3317
3381
  const distribution = selectDistribution({
3318
3382
  experience,
3319
- profile
3383
+ profile: Object.assign(Object.assign({}, profile), {
3384
+ audiences: this.activeAudiences
3385
+ })
3320
3386
  });
3321
3387
  return Object.assign(Object.assign({}, acc), {
3322
3388
  [experience.id]: distribution.index
@@ -1,5 +1,6 @@
1
- import { ExperienceConfiguration, PROFILE_CHANGE } from '@ninetailed/experience.js';
2
- import { NinetailedPlugin } from '@ninetailed/experience.js-plugin-analytics';
1
+ import { Reference } from '@ninetailed/experience.js-shared';
2
+ import { ExperienceConfiguration, PROFILE_CHANGE, NinetailedPlugin, HasExperienceSelectionMiddleware, ExperienceSelectionMiddleware } from '@ninetailed/experience.js';
3
+ import { Audience } from '@ninetailed/experience.js-utils';
3
4
  import { RenderPluginWrapperComponent } from '@ninetailed/experience.js-react';
4
5
  export declare const NINETAILED_PREVIEW_EVENTS: {
5
6
  previewAudiences: string;
@@ -9,17 +10,19 @@ type NinetailedPreviewPluginOptions = {
9
10
  url?: string;
10
11
  environment?: string;
11
12
  experiences: ExperienceConfiguration[];
13
+ audiences: Audience[];
12
14
  ui?: {
13
15
  opener?: {
14
16
  hide: boolean;
15
17
  };
16
18
  };
17
19
  };
18
- export declare class NinetailedPreviewPlugin extends NinetailedPlugin {
20
+ export declare class NinetailedPreviewPlugin extends NinetailedPlugin implements HasExperienceSelectionMiddleware<Reference> {
19
21
  private readonly options;
20
22
  name: string;
21
23
  private isOpen;
22
24
  private readonly experiences;
25
+ private readonly audienceDefinitions;
23
26
  private audienceOverwrites;
24
27
  private experienceVariantIndexOverwrites;
25
28
  private profile;
@@ -27,6 +30,7 @@ export declare class NinetailedPreviewPlugin extends NinetailedPlugin {
27
30
  private bridge;
28
31
  private renderPluginContext;
29
32
  private renderPluginComponent;
33
+ private onChangeEmitter;
30
34
  constructor(options: NinetailedPreviewPluginOptions);
31
35
  initialize: () => Promise<void>;
32
36
  getRenderWrapper: () => RenderPluginWrapperComponent;
@@ -46,6 +50,7 @@ export declare class NinetailedPreviewPlugin extends NinetailedPlugin {
46
50
  }): void;
47
51
  resetExperience(experienceId: string): void;
48
52
  reset(): void;
53
+ getExperienceSelectionMiddleware: ExperienceSelectionMiddleware<Reference>;
49
54
  private get pluginApi();
50
55
  private get windowApi();
51
56
  private isKnownAudience;
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js-plugin-preview",
3
- "version": "4.1.0-beta.0",
3
+ "version": "4.1.0-beta.2",
4
4
  "module": "./index.js",
5
5
  "main": "./index.cjs",
6
6
  "type": "module",
7
7
  "types": "./index.d.ts",
8
8
  "dependencies": {
9
- "@ninetailed/experience.js-shared": "4.1.0-beta.0",
10
- "@ninetailed/experience.js": "4.1.0-beta.0",
11
- "@ninetailed/experience.js-plugin-analytics": "4.1.0-beta.0",
12
- "@ninetailed/experience.js-utils": "4.0.0-beta.1",
13
- "@ninetailed/experience.js-react": "4.1.0-beta.0",
14
- "@ninetailed/experience.js-preview-bridge": "4.1.0-beta.0",
9
+ "lodash": "4.17.21",
10
+ "@ninetailed/experience.js-shared": "4.1.0-beta.2",
11
+ "@ninetailed/experience.js": "4.1.0-beta.2",
12
+ "@ninetailed/experience.js-utils": "4.1.0-beta.1",
13
+ "@ninetailed/experience.js-react": "4.1.0-beta.2",
14
+ "@ninetailed/experience.js-preview-bridge": "4.1.0-beta.2",
15
15
  "react": "18.2.0",
16
- "uuid": "9.0.0"
16
+ "uuid": "9.0.0",
17
+ "ts-toolbelt": "9.6.0"
17
18
  },
18
19
  "peerDependencies": {}
19
20
  }