@ninetailed/experience.js 4.1.0-beta.0 → 4.1.0-beta.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.
Files changed (33) hide show
  1. package/index.cjs +151 -0
  2. package/index.d.ts +4 -0
  3. package/index.js +148 -2
  4. package/lib/Ninetailed.d.ts +4 -4
  5. package/lib/experience/constants.d.ts +4 -0
  6. package/lib/experience/index.d.ts +1 -0
  7. package/lib/experience/isExperienceMatch.d.ts +4 -0
  8. package/lib/experience/makeExperienceSelectMiddleware.d.ts +19 -0
  9. package/lib/experience/selectActiveExperiments.d.ts +4 -0
  10. package/lib/experience/selectBaselineWithVariants.d.ts +4 -0
  11. package/lib/experience/selectDistribution.d.ts +4 -0
  12. package/lib/experience/selectEligibleExperiences.d.ts +4 -0
  13. package/lib/experience/selectExperience.d.ts +4 -0
  14. package/lib/experience/selectHasVariants.d.ts +4 -0
  15. package/lib/experience/selectVariant.d.ts +4 -0
  16. package/lib/experience/selectVariants.d.ts +4 -0
  17. package/lib/experience/types/Baseline.d.ts +4 -0
  18. package/lib/experience/types/BaselineWithVariants.d.ts +4 -0
  19. package/lib/experience/types/Distribution.d.ts +4 -0
  20. package/lib/experience/types/ExperienceConfiguration.d.ts +8 -0
  21. package/lib/experience/types/Reference.d.ts +4 -0
  22. package/lib/experience/types/VariantRef.d.ts +4 -0
  23. package/lib/experience/utils.d.ts +8 -0
  24. package/lib/guards/hasExperienceSelectionMiddleware.d.ts +3 -0
  25. package/lib/guards/hasOnChangeEmitter.d.ts +2 -0
  26. package/lib/plugins/selectPluginsHavingExperienceSelectionMiddleware.d.ts +4 -0
  27. package/lib/plugins/selectPluginsHavingOnChangeEmitter.d.ts +3 -0
  28. package/lib/types/NinetailedPlugin.d.ts +5 -0
  29. package/lib/{types.d.ts → types/index.d.ts} +4 -3
  30. package/lib/types/interfaces/HasExperienceSelectionMiddleware.d.ts +15 -0
  31. package/lib/types/interfaces/HasOnChangeEmitter.d.ts +4 -0
  32. package/lib/utils/OnChangeEmitter.d.ts +8 -0
  33. package/package.json +3 -3
package/index.cjs CHANGED
@@ -3488,13 +3488,27 @@ const selectVariant$1 = (baseline, variants, {
3488
3488
  };
3489
3489
  };
3490
3490
 
3491
+ class NinetailedPlugin {}
3492
+
3493
+ /**
3494
+ * @deprecated use @ninetailed/experience.js-shared instead
3495
+ * This wil get removed in the next major release
3496
+ */
3491
3497
  const EXPERIENCE_TRAIT_PREFIX = 'nt_experiment_';
3492
3498
 
3499
+ /**
3500
+ * @deprecated use @ninetailed/experience.js-shared instead
3501
+ * This wil get removed in the next major release
3502
+ */
3493
3503
  const selectBaselineWithVariants = (experience, baseline) => {
3494
3504
  var _a;
3495
3505
  return (_a = experience.components.find(baselineWithVariants => baselineWithVariants.baseline.id === baseline.id)) !== null && _a !== void 0 ? _a : null;
3496
3506
  };
3497
3507
 
3508
+ /**
3509
+ * @deprecated use @ninetailed/experience.js-shared instead
3510
+ * This wil get removed in the next major release
3511
+ */
3498
3512
  const selectVariants = (experience, baseline) => {
3499
3513
  const baselineWithVariants = selectBaselineWithVariants(experience, baseline);
3500
3514
  if (!baselineWithVariants) {
@@ -3503,6 +3517,10 @@ const selectVariants = (experience, baseline) => {
3503
3517
  return baselineWithVariants.variants;
3504
3518
  };
3505
3519
 
3520
+ /**
3521
+ * @deprecated use @ninetailed/experience.js-shared instead
3522
+ * This wil get removed in the next major release
3523
+ */
3506
3524
  const selectHasVariants = (experience, baseline) => {
3507
3525
  const variants = selectVariants(experience, baseline);
3508
3526
  return variants.length > 0;
@@ -4045,6 +4063,10 @@ fixRegExpWellKnownSymbolLogic('replace', function (_, nativeReplace, maybeCallNa
4045
4063
  ];
4046
4064
  }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
4047
4065
 
4066
+ /**
4067
+ * @deprecated use @ninetailed/experience.js-shared instead
4068
+ * This wil get removed in the next major release
4069
+ */
4048
4070
  const selectActiveExperiments = (experiments, profile) => {
4049
4071
  const experimentTraits = pickBy__default["default"](profile.traits, (value, key) => key.startsWith(EXPERIENCE_TRAIT_PREFIX) && value === true);
4050
4072
  const experimentTraitsIds = Object.keys(experimentTraits).map(id => id.replace(EXPERIENCE_TRAIT_PREFIX, ''));
@@ -4058,6 +4080,10 @@ const selectActiveExperiments = (experiments, profile) => {
4058
4080
  * When going for an experiment we can only select a active experiment when 1 or more experiments are active
4059
4081
  * If the profile is not in any active experiments, we can select any expermiment
4060
4082
  */
4083
+ /**
4084
+ * @deprecated use @ninetailed/experience.js-shared instead
4085
+ * This wil get removed in the next major release
4086
+ */
4061
4087
  const selectEligibleExperiences = ({
4062
4088
  experiences,
4063
4089
  activeExperiments
@@ -4075,9 +4101,21 @@ const getRandom = text => {
4075
4101
  const random = normalize(hash, LOWER_BOUND, UPPER_BOUND);
4076
4102
  return random;
4077
4103
  };
4104
+ /**
4105
+ * @deprecated use @ninetailed/experience.js-shared instead
4106
+ * This wil get removed in the next major release
4107
+ */
4078
4108
  const getTrafficRandom = (profile, experience) => getRandom(`traffic-${experience.id}-${profile.id}`);
4109
+ /**
4110
+ * @deprecated use @ninetailed/experience.js-shared instead
4111
+ * This wil get removed in the next major release
4112
+ */
4079
4113
  const getDistributionRandom = (profile, experience) => getRandom(`distribution-${experience.id}-${profile.id}`);
4080
4114
 
4115
+ /**
4116
+ * @deprecated use @ninetailed/experience.js-shared instead
4117
+ * This wil get removed in the next major release
4118
+ */
4081
4119
  const isExperienceMatch = ({
4082
4120
  experience,
4083
4121
  activeExperiments,
@@ -4098,6 +4136,10 @@ const isExperienceMatch = ({
4098
4136
  hasActiveExperiment);
4099
4137
  };
4100
4138
 
4139
+ /**
4140
+ * @deprecated use @ninetailed/experience.js-shared instead
4141
+ * This wil get removed in the next major release
4142
+ */
4101
4143
  const selectExperience = ({
4102
4144
  experiences,
4103
4145
  activeExperiments,
@@ -4115,6 +4157,10 @@ const selectExperience = ({
4115
4157
  return selectedExperience !== null && selectedExperience !== void 0 ? selectedExperience : null;
4116
4158
  };
4117
4159
 
4160
+ /**
4161
+ * @deprecated use @ninetailed/experience.js-shared instead
4162
+ * This wil get removed in the next major release
4163
+ */
4118
4164
  const selectDistribution = ({
4119
4165
  experience,
4120
4166
  profile
@@ -4138,6 +4184,10 @@ const selectDistribution = ({
4138
4184
  return distribution;
4139
4185
  };
4140
4186
 
4187
+ /**
4188
+ * @deprecated use @ninetailed/experience.js-shared instead
4189
+ * This wil get removed in the next major release
4190
+ */
4141
4191
  const selectVariant = ({
4142
4192
  baseline,
4143
4193
  experience,
@@ -4329,6 +4379,102 @@ const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
4329
4379
  }), {});
4330
4380
  };
4331
4381
 
4382
+ class OnChangeEmitter {
4383
+ constructor() {
4384
+ this.onChangeListeners = [];
4385
+ }
4386
+ addListener(listener) {
4387
+ this.onChangeListeners.push(listener);
4388
+ return () => {
4389
+ this.removeOnChangeListener(listener);
4390
+ };
4391
+ }
4392
+ invokeListeners() {
4393
+ this.onChangeListeners.forEach(listener => listener());
4394
+ }
4395
+ removeOnChangeListener(listener) {
4396
+ this.onChangeListeners = this.onChangeListeners.filter(l => l !== listener);
4397
+ }
4398
+ }
4399
+
4400
+ const hasOnChangeEmitter = arg => {
4401
+ return typeof arg === 'object' && arg !== null && 'onChangeEmitter' in arg && typeof arg.onChangeEmitter === 'object' && arg.onChangeEmitter !== null && arg.onChangeEmitter.constructor === OnChangeEmitter;
4402
+ };
4403
+
4404
+ const selectPluginsHavingOnChangeEmitter = plugins => {
4405
+ const filteredPlugins = [];
4406
+ for (const plugin of plugins) {
4407
+ if (hasOnChangeEmitter(plugin)) {
4408
+ filteredPlugins.push(plugin);
4409
+ }
4410
+ }
4411
+ return filteredPlugins;
4412
+ };
4413
+
4414
+ const hasExperienceSelectionMiddleware = arg => {
4415
+ return typeof arg === 'object' && arg !== null && 'getExperienceSelectionMiddleware' in arg && typeof arg.getExperienceSelectionMiddleware === 'function';
4416
+ };
4417
+
4418
+ const selectPluginsHavingExperienceSelectionMiddleware = plugins => {
4419
+ const filteredPlugins = [];
4420
+ for (const plugin of plugins) {
4421
+ if (hasExperienceSelectionMiddleware(plugin)) {
4422
+ filteredPlugins.push(plugin);
4423
+ }
4424
+ }
4425
+ return filteredPlugins;
4426
+ };
4427
+
4428
+ const createPassThroughMiddleware = () => {
4429
+ return ({
4430
+ experience,
4431
+ variant
4432
+ }) => {
4433
+ return {
4434
+ experience,
4435
+ variant
4436
+ };
4437
+ };
4438
+ };
4439
+ const makeExperienceSelectMiddleware = ({
4440
+ plugins,
4441
+ onChange,
4442
+ experiences,
4443
+ baseline,
4444
+ profile
4445
+ }) => {
4446
+ let removeChangeListeners = [];
4447
+ const pluginsHavingChangeEmitters = selectPluginsHavingOnChangeEmitter(plugins);
4448
+ const prepareMiddleware = () => {
4449
+ if (profile === null) {
4450
+ return createPassThroughMiddleware();
4451
+ }
4452
+ const pluginsWithMiddleware = selectPluginsHavingExperienceSelectionMiddleware(plugins);
4453
+ const middlewareFunctions = pluginsWithMiddleware.map(plugin => plugin.getExperienceSelectionMiddleware({
4454
+ experiences,
4455
+ baseline
4456
+ }));
4457
+ return experience_jsShared.pipe(...middlewareFunctions);
4458
+ };
4459
+ const addListeners = () => {
4460
+ removeChangeListeners = pluginsHavingChangeEmitters.map(plugin => {
4461
+ const listener = () => {
4462
+ onChange();
4463
+ };
4464
+ return plugin.onChangeEmitter.addListener(listener);
4465
+ });
4466
+ };
4467
+ const removeListeners = () => {
4468
+ removeChangeListeners.forEach(listener => listener());
4469
+ };
4470
+ const middleware = prepareMiddleware();
4471
+ return {
4472
+ addListeners,
4473
+ removeListeners,
4474
+ middleware
4475
+ };
4476
+ };
4477
+
4332
4478
  exports.ANONYMOUS_ID = ANONYMOUS_ID;
4333
4479
  exports.CONSENT = CONSENT;
4334
4480
  exports.DEBUG_FLAG = DEBUG_FLAG;
@@ -4336,6 +4482,8 @@ exports.EMPTY_MERGE_ID = EMPTY_MERGE_ID;
4336
4482
  exports.EXPERIENCE_TRAIT_PREFIX = EXPERIENCE_TRAIT_PREFIX;
4337
4483
  exports.LEGACY_ANONYMOUS_ID = LEGACY_ANONYMOUS_ID;
4338
4484
  exports.Ninetailed = Ninetailed;
4485
+ exports.NinetailedPlugin = NinetailedPlugin;
4486
+ exports.OnChangeEmitter = OnChangeEmitter;
4339
4487
  exports.PLUGIN_NAME = PLUGIN_NAME;
4340
4488
  exports.PROFILE_CHANGE = PROFILE_CHANGE;
4341
4489
  exports.PROFILE_FALLBACK_CACHE = PROFILE_FALLBACK_CACHE;
@@ -4343,6 +4491,7 @@ exports.PROFILE_RESET = PROFILE_RESET;
4343
4491
  exports.SET_ENABLED_FEATURES = SET_ENABLED_FEATURES;
4344
4492
  exports.decodeExperienceVariantsMap = decodeExperienceVariantsMap;
4345
4493
  exports.isExperienceMatch = isExperienceMatch;
4494
+ exports.makeExperienceSelectMiddleware = makeExperienceSelectMiddleware;
4346
4495
  exports.ninetailedPlugin = ninetailedPlugin;
4347
4496
  exports.selectActiveExperiments = selectActiveExperiments;
4348
4497
  exports.selectDistribution = selectDistribution;
@@ -4352,4 +4501,6 @@ exports.selectExperienceBaselineWithVariants = selectBaselineWithVariants;
4352
4501
  exports.selectExperienceVariant = selectVariant;
4353
4502
  exports.selectExperienceVariants = selectVariants;
4354
4503
  exports.selectHasExperienceVariants = selectHasVariants;
4504
+ exports.selectPluginsHavingExperienceSelectionMiddleware = selectPluginsHavingExperienceSelectionMiddleware;
4505
+ exports.selectPluginsHavingOnChangeEmitter = selectPluginsHavingOnChangeEmitter;
4355
4506
  exports.selectVariant = selectVariant$1;
package/index.d.ts CHANGED
@@ -3,4 +3,8 @@ export * from './lib/Ninetailed';
3
3
  export * from './lib/selectVariant';
4
4
  export * from './lib/types';
5
5
  export * from './lib/experience';
6
+ export * from './lib/plugins/selectPluginsHavingExperienceSelectionMiddleware';
7
+ export * from './lib/plugins/selectPluginsHavingOnChangeEmitter';
8
+ export * from './lib/types/interfaces/HasExperienceSelectionMiddleware';
9
+ export * from './lib/utils/OnChangeEmitter';
6
10
  export type { Profile } from '@ninetailed/experience.js-shared';
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import unionBy from 'lodash/unionBy';
2
- import { FEATURES, logger, ConsoleLogSink, buildPageEvent, buildTrackEvent, buildIdentifyEvent, NinetailedApiClient, OnLogLogSink, OnErrorLogSink, PageviewProperties, Properties, Traits } from '@ninetailed/experience.js-shared';
2
+ import { FEATURES, logger, ConsoleLogSink, buildPageEvent, buildTrackEvent, buildIdentifyEvent, NinetailedApiClient, OnLogLogSink, OnErrorLogSink, PageviewProperties, Properties, Traits, pipe } from '@ninetailed/experience.js-shared';
3
3
  import Analytics from 'analytics';
4
4
  import { HAS_SEEN_EXPERIENCE, HAS_SEEN_COMPONENT } from '@ninetailed/experience.js-plugin-analytics';
5
5
  import flatten from 'lodash/flatten';
@@ -3475,13 +3475,27 @@ const selectVariant$1 = (baseline, variants, {
3475
3475
  };
3476
3476
  };
3477
3477
 
3478
+ class NinetailedPlugin {}
3479
+
3480
+ /**
3481
+ * @deprecated use @ninetailed/experience.js-shared instead
3482
+ * This wil get removed in the next major release
3483
+ */
3478
3484
  const EXPERIENCE_TRAIT_PREFIX = 'nt_experiment_';
3479
3485
 
3486
+ /**
3487
+ * @deprecated use @ninetailed/experience.js-shared instead
3488
+ * This wil get removed in the next major release
3489
+ */
3480
3490
  const selectBaselineWithVariants = (experience, baseline) => {
3481
3491
  var _a;
3482
3492
  return (_a = experience.components.find(baselineWithVariants => baselineWithVariants.baseline.id === baseline.id)) !== null && _a !== void 0 ? _a : null;
3483
3493
  };
3484
3494
 
3495
+ /**
3496
+ * @deprecated use @ninetailed/experience.js-shared instead
3497
+ * This wil get removed in the next major release
3498
+ */
3485
3499
  const selectVariants = (experience, baseline) => {
3486
3500
  const baselineWithVariants = selectBaselineWithVariants(experience, baseline);
3487
3501
  if (!baselineWithVariants) {
@@ -3490,6 +3504,10 @@ const selectVariants = (experience, baseline) => {
3490
3504
  return baselineWithVariants.variants;
3491
3505
  };
3492
3506
 
3507
+ /**
3508
+ * @deprecated use @ninetailed/experience.js-shared instead
3509
+ * This wil get removed in the next major release
3510
+ */
3493
3511
  const selectHasVariants = (experience, baseline) => {
3494
3512
  const variants = selectVariants(experience, baseline);
3495
3513
  return variants.length > 0;
@@ -4032,6 +4050,10 @@ fixRegExpWellKnownSymbolLogic('replace', function (_, nativeReplace, maybeCallNa
4032
4050
  ];
4033
4051
  }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
4034
4052
 
4053
+ /**
4054
+ * @deprecated use @ninetailed/experience.js-shared instead
4055
+ * This wil get removed in the next major release
4056
+ */
4035
4057
  const selectActiveExperiments = (experiments, profile) => {
4036
4058
  const experimentTraits = pickBy(profile.traits, (value, key) => key.startsWith(EXPERIENCE_TRAIT_PREFIX) && value === true);
4037
4059
  const experimentTraitsIds = Object.keys(experimentTraits).map(id => id.replace(EXPERIENCE_TRAIT_PREFIX, ''));
@@ -4045,6 +4067,10 @@ const selectActiveExperiments = (experiments, profile) => {
4045
4067
  * When going for an experiment we can only select a active experiment when 1 or more experiments are active
4046
4068
  * If the profile is not in any active experiments, we can select any expermiment
4047
4069
  */
4070
+ /**
4071
+ * @deprecated use @ninetailed/experience.js-shared instead
4072
+ * This wil get removed in the next major release
4073
+ */
4048
4074
  const selectEligibleExperiences = ({
4049
4075
  experiences,
4050
4076
  activeExperiments
@@ -4062,9 +4088,21 @@ const getRandom = text => {
4062
4088
  const random = normalize(hash, LOWER_BOUND, UPPER_BOUND);
4063
4089
  return random;
4064
4090
  };
4091
+ /**
4092
+ * @deprecated use @ninetailed/experience.js-shared instead
4093
+ * This wil get removed in the next major release
4094
+ */
4065
4095
  const getTrafficRandom = (profile, experience) => getRandom(`traffic-${experience.id}-${profile.id}`);
4096
+ /**
4097
+ * @deprecated use @ninetailed/experience.js-shared instead
4098
+ * This wil get removed in the next major release
4099
+ */
4066
4100
  const getDistributionRandom = (profile, experience) => getRandom(`distribution-${experience.id}-${profile.id}`);
4067
4101
 
4102
+ /**
4103
+ * @deprecated use @ninetailed/experience.js-shared instead
4104
+ * This wil get removed in the next major release
4105
+ */
4068
4106
  const isExperienceMatch = ({
4069
4107
  experience,
4070
4108
  activeExperiments,
@@ -4085,6 +4123,10 @@ const isExperienceMatch = ({
4085
4123
  hasActiveExperiment);
4086
4124
  };
4087
4125
 
4126
+ /**
4127
+ * @deprecated use @ninetailed/experience.js-shared instead
4128
+ * This wil get removed in the next major release
4129
+ */
4088
4130
  const selectExperience = ({
4089
4131
  experiences,
4090
4132
  activeExperiments,
@@ -4102,6 +4144,10 @@ const selectExperience = ({
4102
4144
  return selectedExperience !== null && selectedExperience !== void 0 ? selectedExperience : null;
4103
4145
  };
4104
4146
 
4147
+ /**
4148
+ * @deprecated use @ninetailed/experience.js-shared instead
4149
+ * This wil get removed in the next major release
4150
+ */
4105
4151
  const selectDistribution = ({
4106
4152
  experience,
4107
4153
  profile
@@ -4125,6 +4171,10 @@ const selectDistribution = ({
4125
4171
  return distribution;
4126
4172
  };
4127
4173
 
4174
+ /**
4175
+ * @deprecated use @ninetailed/experience.js-shared instead
4176
+ * This wil get removed in the next major release
4177
+ */
4128
4178
  const selectVariant = ({
4129
4179
  baseline,
4130
4180
  experience,
@@ -4316,4 +4366,100 @@ const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
4316
4366
  }), {});
4317
4367
  };
4318
4368
 
4319
- export { ANONYMOUS_ID, CONSENT, DEBUG_FLAG, EMPTY_MERGE_ID, EXPERIENCE_TRAIT_PREFIX, LEGACY_ANONYMOUS_ID, Ninetailed, PLUGIN_NAME, PROFILE_CHANGE, PROFILE_FALLBACK_CACHE, PROFILE_RESET, SET_ENABLED_FEATURES, decodeExperienceVariantsMap, isExperienceMatch, ninetailedPlugin, selectActiveExperiments, selectDistribution, selectEligibleExperiences, selectExperience, selectBaselineWithVariants as selectExperienceBaselineWithVariants, selectVariant as selectExperienceVariant, selectVariants as selectExperienceVariants, selectHasVariants as selectHasExperienceVariants, selectVariant$1 as selectVariant };
4369
+ class OnChangeEmitter {
4370
+ constructor() {
4371
+ this.onChangeListeners = [];
4372
+ }
4373
+ addListener(listener) {
4374
+ this.onChangeListeners.push(listener);
4375
+ return () => {
4376
+ this.removeOnChangeListener(listener);
4377
+ };
4378
+ }
4379
+ invokeListeners() {
4380
+ this.onChangeListeners.forEach(listener => listener());
4381
+ }
4382
+ removeOnChangeListener(listener) {
4383
+ this.onChangeListeners = this.onChangeListeners.filter(l => l !== listener);
4384
+ }
4385
+ }
4386
+
4387
+ const hasOnChangeEmitter = arg => {
4388
+ return typeof arg === 'object' && arg !== null && 'onChangeEmitter' in arg && typeof arg.onChangeEmitter === 'object' && arg.onChangeEmitter !== null && arg.onChangeEmitter.constructor === OnChangeEmitter;
4389
+ };
4390
+
4391
+ const selectPluginsHavingOnChangeEmitter = plugins => {
4392
+ const filteredPlugins = [];
4393
+ for (const plugin of plugins) {
4394
+ if (hasOnChangeEmitter(plugin)) {
4395
+ filteredPlugins.push(plugin);
4396
+ }
4397
+ }
4398
+ return filteredPlugins;
4399
+ };
4400
+
4401
+ const hasExperienceSelectionMiddleware = arg => {
4402
+ return typeof arg === 'object' && arg !== null && 'getExperienceSelectionMiddleware' in arg && typeof arg.getExperienceSelectionMiddleware === 'function';
4403
+ };
4404
+
4405
+ const selectPluginsHavingExperienceSelectionMiddleware = plugins => {
4406
+ const filteredPlugins = [];
4407
+ for (const plugin of plugins) {
4408
+ if (hasExperienceSelectionMiddleware(plugin)) {
4409
+ filteredPlugins.push(plugin);
4410
+ }
4411
+ }
4412
+ return filteredPlugins;
4413
+ };
4414
+
4415
+ const createPassThroughMiddleware = () => {
4416
+ return ({
4417
+ experience,
4418
+ variant
4419
+ }) => {
4420
+ return {
4421
+ experience,
4422
+ variant
4423
+ };
4424
+ };
4425
+ };
4426
+ const makeExperienceSelectMiddleware = ({
4427
+ plugins,
4428
+ onChange,
4429
+ experiences,
4430
+ baseline,
4431
+ profile
4432
+ }) => {
4433
+ let removeChangeListeners = [];
4434
+ const pluginsHavingChangeEmitters = selectPluginsHavingOnChangeEmitter(plugins);
4435
+ const prepareMiddleware = () => {
4436
+ if (profile === null) {
4437
+ return createPassThroughMiddleware();
4438
+ }
4439
+ const pluginsWithMiddleware = selectPluginsHavingExperienceSelectionMiddleware(plugins);
4440
+ const middlewareFunctions = pluginsWithMiddleware.map(plugin => plugin.getExperienceSelectionMiddleware({
4441
+ experiences,
4442
+ baseline
4443
+ }));
4444
+ return pipe(...middlewareFunctions);
4445
+ };
4446
+ const addListeners = () => {
4447
+ removeChangeListeners = pluginsHavingChangeEmitters.map(plugin => {
4448
+ const listener = () => {
4449
+ onChange();
4450
+ };
4451
+ return plugin.onChangeEmitter.addListener(listener);
4452
+ });
4453
+ };
4454
+ const removeListeners = () => {
4455
+ removeChangeListeners.forEach(listener => listener());
4456
+ };
4457
+ const middleware = prepareMiddleware();
4458
+ return {
4459
+ addListeners,
4460
+ removeListeners,
4461
+ middleware
4462
+ };
4463
+ };
4464
+
4465
+ export { ANONYMOUS_ID, CONSENT, DEBUG_FLAG, EMPTY_MERGE_ID, EXPERIENCE_TRAIT_PREFIX, LEGACY_ANONYMOUS_ID, Ninetailed, NinetailedPlugin, OnChangeEmitter, PLUGIN_NAME, PROFILE_CHANGE, PROFILE_FALLBACK_CACHE, PROFILE_RESET, SET_ENABLED_FEATURES, decodeExperienceVariantsMap, isExperienceMatch, makeExperienceSelectMiddleware, ninetailedPlugin, selectActiveExperiments, selectDistribution, selectEligibleExperiences, selectExperience, selectBaselineWithVariants as selectExperienceBaselineWithVariants, selectVariant as selectExperienceVariant, selectVariants as selectExperienceVariants, selectHasVariants as selectHasExperienceVariants, selectPluginsHavingExperienceSelectionMiddleware, selectPluginsHavingOnChangeEmitter, selectVariant$1 as selectVariant };
@@ -1,6 +1,6 @@
1
- import { AnalyticsPlugin } from 'analytics';
1
+ /// <reference types="analytics" />
2
2
  import { Locale, Traits, Profile, OnLogHandler, OnErrorHandler, Logger, PageviewProperties, Properties, NinetailedApiClient, NinetailedApiClientOptions } from '@ninetailed/experience.js-shared';
3
- import { EventFunctionOptions, NinetailedInstance, OnIsInitializedCallback, OnProfileChangeCallback, ProfileState, TrackHasSeenComponent, TrackHasSeenExperience } from './types';
3
+ import { EventFunctionOptions, NinetailedInstance, NinetailedPlugin, OnIsInitializedCallback, OnProfileChangeCallback, ProfileState, TrackHasSeenComponent, TrackHasSeenExperience } from './types';
4
4
  declare global {
5
5
  interface Window {
6
6
  ninetailed?: {
@@ -14,7 +14,7 @@ declare global {
14
14
  type Options = {
15
15
  url?: string;
16
16
  locale?: Locale;
17
- plugins?: (AnalyticsPlugin | AnalyticsPlugin[])[];
17
+ plugins?: (NinetailedPlugin | NinetailedPlugin[])[];
18
18
  profile?: Profile;
19
19
  requestTimeout?: number;
20
20
  onLog?: OnLogHandler;
@@ -27,7 +27,7 @@ export declare class Ninetailed implements NinetailedInstance {
27
27
  private isInitialized;
28
28
  private readonly apiClient;
29
29
  private readonly eventQueue;
30
- readonly plugins: AnalyticsPlugin[];
30
+ readonly plugins: NinetailedPlugin[];
31
31
  readonly logger: Logger;
32
32
  constructor(ninetailedApiClientInstanceOrOptions: NinetailedApiClientInstanceOrOptions, { plugins, url, profile, locale, requestTimeout, onLog, onError, }?: Options);
33
33
  page: (data?: Partial<PageviewProperties>, options?: EventFunctionOptions) => Promise<import("./types").FlushResult>;
@@ -1 +1,5 @@
1
+ /**
2
+ * @deprecated use @ninetailed/experience.js-shared instead
3
+ * This wil get removed in the next major release
4
+ */
1
5
  export declare const EXPERIENCE_TRAIT_PREFIX = "nt_experiment_";
@@ -10,3 +10,4 @@ export { selectVariant as selectExperienceVariant } from './selectVariant';
10
10
  export { isExperienceMatch } from './isExperienceMatch';
11
11
  export { selectDistribution } from './selectDistribution';
12
12
  export { decodeExperienceVariantsMap } from './decodeExperienceVariantsMap';
13
+ export { makeExperienceSelectMiddleware } from './makeExperienceSelectMiddleware';
@@ -5,5 +5,9 @@ type IsExperienceMatchArgs = {
5
5
  activeExperiments: ExperienceConfiguration<any>[];
6
6
  profile: Profile;
7
7
  };
8
+ /**
9
+ * @deprecated use @ninetailed/experience.js-shared instead
10
+ * This wil get removed in the next major release
11
+ */
8
12
  export declare const isExperienceMatch: ({ experience, activeExperiments, profile, }: IsExperienceMatchArgs) => boolean;
9
13
  export {};
@@ -0,0 +1,19 @@
1
+ import { ExperienceConfiguration, Profile, Reference } from '@ninetailed/experience.js-shared';
2
+ import { NinetailedPlugin } from '../types/NinetailedPlugin';
3
+ import { ExperienceSelectionMiddlewareReturnArg } from '../types/interfaces/HasExperienceSelectionMiddleware';
4
+ type MakeExperienceSelectMiddlewareArg = {
5
+ plugins: NinetailedPlugin[];
6
+ experiences: ExperienceConfiguration<Reference>[];
7
+ baseline: Reference;
8
+ profile: Profile | null;
9
+ onChange: () => void;
10
+ };
11
+ export declare const makeExperienceSelectMiddleware: ({ plugins, onChange, experiences, baseline, profile, }: MakeExperienceSelectMiddlewareArg) => {
12
+ addListeners: () => void;
13
+ removeListeners: () => void;
14
+ middleware: ({ experience, variant, }: ExperienceSelectionMiddlewareReturnArg<Reference>) => {
15
+ experience: ExperienceConfiguration<Reference> | null;
16
+ variant: Reference | null;
17
+ };
18
+ };
19
+ export {};
@@ -1,3 +1,7 @@
1
1
  import { Profile } from '@ninetailed/experience.js-shared';
2
2
  import { ExperienceConfiguration, Reference } from './types';
3
+ /**
4
+ * @deprecated use @ninetailed/experience.js-shared instead
5
+ * This wil get removed in the next major release
6
+ */
3
7
  export declare const selectActiveExperiments: <Variant extends Reference>(experiments: ExperienceConfiguration<Variant>[], profile: Profile) => ExperienceConfiguration<Variant>[];
@@ -1,2 +1,6 @@
1
1
  import { Baseline, BaselineWithVariants, ExperienceConfiguration, Reference } from './types';
2
+ /**
3
+ * @deprecated use @ninetailed/experience.js-shared instead
4
+ * This wil get removed in the next major release
5
+ */
2
6
  export declare const selectBaselineWithVariants: <Variant extends Reference>(experience: ExperienceConfiguration<Variant>, baseline: Baseline) => BaselineWithVariants<Variant> | null;
@@ -4,5 +4,9 @@ type SelectDistributionArgs<Variant extends Reference> = {
4
4
  experience: ExperienceConfiguration<Variant>;
5
5
  profile: Profile;
6
6
  };
7
+ /**
8
+ * @deprecated use @ninetailed/experience.js-shared instead
9
+ * This wil get removed in the next major release
10
+ */
7
11
  export declare const selectDistribution: <Variant extends Reference>({ experience, profile, }: SelectDistributionArgs<Variant>) => Distribution;
8
12
  export {};
@@ -8,5 +8,9 @@ type SelectEligibleExperiencesArgs<Variant extends Reference> = {
8
8
  * When going for an experiment we can only select a active experiment when 1 or more experiments are active
9
9
  * If the profile is not in any active experiments, we can select any expermiment
10
10
  */
11
+ /**
12
+ * @deprecated use @ninetailed/experience.js-shared instead
13
+ * This wil get removed in the next major release
14
+ */
11
15
  export declare const selectEligibleExperiences: <Variant extends Reference>({ experiences, activeExperiments, }: SelectEligibleExperiencesArgs<Variant>) => ExperienceConfiguration<Variant>[];
12
16
  export {};
@@ -5,5 +5,9 @@ type SelectExprienceArgs<Variant extends Reference> = {
5
5
  activeExperiments: ExperienceConfiguration<Variant>[];
6
6
  profile: Profile;
7
7
  };
8
+ /**
9
+ * @deprecated use @ninetailed/experience.js-shared instead
10
+ * This wil get removed in the next major release
11
+ */
8
12
  export declare const selectExperience: <Variant extends Reference>({ experiences, activeExperiments, profile, }: SelectExprienceArgs<Variant>) => ExperienceConfiguration<Variant> | null;
9
13
  export {};
@@ -1,2 +1,6 @@
1
1
  import { Baseline, ExperienceConfiguration, Reference } from './types';
2
+ /**
3
+ * @deprecated use @ninetailed/experience.js-shared instead
4
+ * This wil get removed in the next major release
5
+ */
2
6
  export declare const selectHasVariants: <Variant extends Reference>(experience: ExperienceConfiguration<Variant>, baseline: Baseline) => boolean;
@@ -5,5 +5,9 @@ type SelectVariantArgs<Variant extends Reference> = {
5
5
  experience: ExperienceConfiguration<Variant>;
6
6
  profile: Profile;
7
7
  };
8
+ /**
9
+ * @deprecated use @ninetailed/experience.js-shared instead
10
+ * This wil get removed in the next major release
11
+ */
8
12
  export declare const selectVariant: <Variant extends Reference>({ baseline, experience, profile, }: SelectVariantArgs<Variant>) => Variant | VariantRef | null;
9
13
  export {};
@@ -1,2 +1,6 @@
1
1
  import { Baseline, ExperienceConfiguration, Reference, VariantRef } from './types';
2
+ /**
3
+ * @deprecated use @ninetailed/experience.js-shared instead
4
+ * This wil get removed in the next major release
5
+ */
2
6
  export declare const selectVariants: <Variant extends Reference>(experience: ExperienceConfiguration<Variant>, baseline: Baseline) => (Variant | VariantRef)[];
@@ -1,2 +1,6 @@
1
1
  import { Reference } from './Reference';
2
+ /**
3
+ * @deprecated use @ninetailed/experience.js-shared instead
4
+ * This wil get removed in the next major release
5
+ */
2
6
  export type Baseline<P = unknown> = P & Reference;
@@ -1,6 +1,10 @@
1
1
  import { Baseline } from './Baseline';
2
2
  import { Reference } from './Reference';
3
3
  import { VariantRef } from './VariantRef';
4
+ /**
5
+ * @deprecated use @ninetailed/experience.js-shared instead
6
+ * This wil get removed in the next major release
7
+ */
4
8
  export type BaselineWithVariants<Variant extends Reference> = {
5
9
  baseline: Baseline;
6
10
  variants: (Variant | VariantRef)[];
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @deprecated use @ninetailed/experience.js-shared instead
3
+ * This wil get removed in the next major release
4
+ */
1
5
  export type Distribution = {
2
6
  index: number;
3
7
  start: number;
@@ -1,7 +1,15 @@
1
1
  import { BaselineWithVariants } from './BaselineWithVariants';
2
2
  import { Distribution } from './Distribution';
3
3
  import { Reference } from './Reference';
4
+ /**
5
+ * @deprecated use @ninetailed/experience.js-shared instead
6
+ * This wil get removed in the next major release
7
+ */
4
8
  export type ExperienceType = 'nt_personalization' | 'nt_experiment';
9
+ /**
10
+ * @deprecated use @ninetailed/experience.js-shared instead
11
+ * This wil get removed in the next major release
12
+ */
5
13
  export type ExperienceConfiguration<Variant extends Reference = Reference> = {
6
14
  id: string;
7
15
  type: ExperienceType;
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @deprecated use @ninetailed/experience.js-shared instead
3
+ * This wil get removed in the next major release
4
+ */
1
5
  export type Reference = {
2
6
  id: string;
3
7
  };
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @deprecated use @ninetailed/experience.js-shared instead
3
+ * This wil get removed in the next major release
4
+ */
1
5
  export type VariantRef = {
2
6
  id: string;
3
7
  hidden: boolean;
@@ -1,4 +1,12 @@
1
1
  import { Profile } from '@ninetailed/experience.js-shared';
2
2
  import { ExperienceConfiguration } from './types';
3
+ /**
4
+ * @deprecated use @ninetailed/experience.js-shared instead
5
+ * This wil get removed in the next major release
6
+ */
3
7
  export declare const getTrafficRandom: (profile: Profile, experience: ExperienceConfiguration<any>) => number;
8
+ /**
9
+ * @deprecated use @ninetailed/experience.js-shared instead
10
+ * This wil get removed in the next major release
11
+ */
4
12
  export declare const getDistributionRandom: (profile: Profile, experience: ExperienceConfiguration<any>) => number;
@@ -0,0 +1,3 @@
1
+ import { Reference } from '@ninetailed/experience.js-shared';
2
+ import { HasExperienceSelectionMiddleware } from '../types/interfaces/HasExperienceSelectionMiddleware';
3
+ export declare const hasExperienceSelectionMiddleware: <Variant extends Reference>(arg: unknown) => arg is HasExperienceSelectionMiddleware<Variant>;
@@ -0,0 +1,2 @@
1
+ import { HasOnChangeEmitter } from '../types/interfaces/HasOnChangeEmitter';
2
+ export declare const hasOnChangeEmitter: (arg: unknown) => arg is HasOnChangeEmitter;
@@ -0,0 +1,4 @@
1
+ import { Reference } from '@ninetailed/experience.js-shared';
2
+ import { HasExperienceSelectionMiddleware } from '../types/interfaces/HasExperienceSelectionMiddleware';
3
+ import { NinetailedPlugin } from '../types/NinetailedPlugin';
4
+ export declare const selectPluginsHavingExperienceSelectionMiddleware: <Variant extends Reference>(plugins: NinetailedPlugin[]) => HasExperienceSelectionMiddleware<Variant>[];
@@ -0,0 +1,3 @@
1
+ import { NinetailedPlugin } from '../types/NinetailedPlugin';
2
+ import { HasOnChangeEmitter } from '../types/interfaces/HasOnChangeEmitter';
3
+ export declare const selectPluginsHavingOnChangeEmitter: (plugins: NinetailedPlugin[]) => HasOnChangeEmitter[];
@@ -0,0 +1,5 @@
1
+ import { AnalyticsPlugin } from 'analytics';
2
+ export declare abstract class NinetailedPlugin implements AnalyticsPlugin {
3
+ [x: string]: unknown;
4
+ abstract readonly name: string;
5
+ }
@@ -1,6 +1,7 @@
1
1
  import { TrackComponentProperties, TrackExperienceProperties } from '@ninetailed/experience.js-plugin-analytics';
2
2
  import { Logger, PageviewProperties, Profile, Properties, Traits } from '@ninetailed/experience.js-shared';
3
- import { AnalyticsPlugin, DetachListeners } from 'analytics';
3
+ import { DetachListeners } from 'analytics';
4
+ import { NinetailedPlugin } from './NinetailedPlugin';
4
5
  type Loading = {
5
6
  status: 'loading';
6
7
  profile: null;
@@ -49,8 +50,8 @@ export interface NinetailedInstance {
49
50
  debug: Debug;
50
51
  profileState: ProfileState;
51
52
  onProfileChange: OnProfileChange;
52
- plugins: AnalyticsPlugin[];
53
+ plugins: NinetailedPlugin[];
53
54
  logger: Logger;
54
55
  onIsInitialized: OnIsInitialized;
55
56
  }
56
- export {};
57
+ export { NinetailedPlugin };
@@ -0,0 +1,15 @@
1
+ import { ExperienceConfiguration, Reference } from '@ninetailed/experience.js-shared';
2
+ export type ExperienceSelectionMiddlewareReturnArg<Variant extends Reference> = {
3
+ experience: ExperienceConfiguration<Variant> | null;
4
+ variant: Variant | null;
5
+ };
6
+ type ExperienceSelectionMiddlewareReturn<Variant extends Reference> = (arg: ExperienceSelectionMiddlewareReturnArg<Variant>) => ExperienceSelectionMiddlewareReturnArg<Variant>;
7
+ type ExperienceSelectionMiddlewareArg<Variant extends Reference> = {
8
+ experiences: ExperienceConfiguration<Variant>[];
9
+ baseline: Reference;
10
+ };
11
+ export type ExperienceSelectionMiddleware<Variant extends Reference> = (arg: ExperienceSelectionMiddlewareArg<Variant>) => ExperienceSelectionMiddlewareReturn<Variant>;
12
+ export interface HasExperienceSelectionMiddleware<Variant extends Reference> {
13
+ getExperienceSelectionMiddleware: ExperienceSelectionMiddleware<Variant>;
14
+ }
15
+ export {};
@@ -0,0 +1,4 @@
1
+ import { OnChangeEmitter } from '../../utils/OnChangeEmitter';
2
+ export interface HasOnChangeEmitter {
3
+ onChangeEmitter: OnChangeEmitter;
4
+ }
@@ -0,0 +1,8 @@
1
+ export type OnChangeListener = () => void;
2
+ export type RemoveOnChangeListener = () => void;
3
+ export declare class OnChangeEmitter {
4
+ private onChangeListeners;
5
+ addListener(listener: OnChangeListener): RemoveOnChangeListener;
6
+ invokeListeners(): void;
7
+ private removeOnChangeListener;
8
+ }
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js",
3
- "version": "4.1.0-beta.0",
3
+ "version": "4.1.0-beta.1",
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",
9
+ "@ninetailed/experience.js-shared": "4.1.0-beta.1",
10
10
  "analytics": "0.8.1",
11
11
  "lodash": "4.17.21",
12
12
  "murmurhash-js": "1.0.0",
13
- "@ninetailed/experience.js-plugin-analytics": "4.1.0-beta.0"
13
+ "@ninetailed/experience.js-plugin-analytics": "4.1.0-beta.1"
14
14
  },
15
15
  "peerDependencies": {}
16
16
  }