@ninetailed/experience.js 7.5.0-beta.9 → 7.6.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.
package/index.cjs CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var experience_jsShared = require('@ninetailed/experience.js-shared');
6
6
  var Analytics = require('analytics');
7
+ var uuid = require('uuid');
7
8
  var zod = require('zod');
8
9
 
9
10
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -15,6 +16,7 @@ const HAS_SEEN_ELEMENT = 'has_seen_element';
15
16
  const COMPONENT = 'component';
16
17
  const COMPONENT_START = 'componentStart';
17
18
  const PAGE_HIDDEN = 'page_hidden';
19
+ const HAS_SEEN_STICKY_COMPONENT = 'sticky_component_view';
18
20
 
19
21
  /******************************************************************************
20
22
  Copyright (c) Microsoft Corporation.
@@ -272,6 +274,20 @@ const ninetailedCorePlugin = ({
272
274
  ctx
273
275
  }));
274
276
  }),
277
+ [HAS_SEEN_STICKY_COMPONENT]: ({
278
+ payload
279
+ }) => __awaiter(void 0, void 0, void 0, function* () {
280
+ experience_jsShared.logger.info('Sending Sticky Components event.');
281
+ const ctx = buildContext();
282
+ return enqueueEvent(experience_jsShared.buildComponentViewEvent({
283
+ messageId: payload.meta.rid,
284
+ timestamp: payload.meta.ts,
285
+ componentId: payload.componentId,
286
+ experienceId: payload.experienceId,
287
+ variantIndex: payload.variantIndex,
288
+ ctx
289
+ }));
290
+ }),
275
291
  setItemStart: ({
276
292
  abort,
277
293
  payload
@@ -368,6 +384,189 @@ const isInterestedInHiddenPage = arg => {
368
384
  return typeof arg === 'object' && arg !== null && PAGE_HIDDEN in arg && typeof arg[PAGE_HIDDEN] === 'function';
369
385
  };
370
386
 
387
+ const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
388
+ return encodedExperienceVariantsMap.split(',').map(experienceIdWithVariant => {
389
+ const [experienceId, _variantIndex] = experienceIdWithVariant.split('=');
390
+ const variantIndex = parseInt(_variantIndex);
391
+ if (!experienceId || !variantIndex) {
392
+ return null;
393
+ }
394
+ return {
395
+ experienceId,
396
+ variantIndex
397
+ };
398
+ }).filter(x => !!x).reduce((acc, curr) => Object.assign(Object.assign({}, acc), {
399
+ [curr.experienceId]: curr.variantIndex
400
+ }), {});
401
+ };
402
+
403
+ class OnChangeEmitter {
404
+ constructor() {
405
+ this.onChangeListeners = [];
406
+ }
407
+ addListener(listener) {
408
+ this.onChangeListeners.push(listener);
409
+ return () => {
410
+ this.removeOnChangeListener(listener);
411
+ };
412
+ }
413
+ invokeListeners() {
414
+ this.onChangeListeners.forEach(listener => listener());
415
+ }
416
+ removeOnChangeListener(listener) {
417
+ this.onChangeListeners = this.onChangeListeners.filter(l => l !== listener);
418
+ }
419
+ }
420
+
421
+ const hasOnChangeEmitter = arg => {
422
+ return typeof arg === 'object' && arg !== null && 'onChangeEmitter' in arg && typeof arg.onChangeEmitter === 'object' && arg.onChangeEmitter !== null && arg.onChangeEmitter.constructor === OnChangeEmitter;
423
+ };
424
+
425
+ const selectPluginsHavingOnChangeEmitter = plugins => {
426
+ const filteredPlugins = [];
427
+ for (const plugin of plugins) {
428
+ if (hasOnChangeEmitter(plugin)) {
429
+ filteredPlugins.push(plugin);
430
+ }
431
+ }
432
+ return filteredPlugins;
433
+ };
434
+
435
+ const hasExperienceSelectionMiddleware = arg => {
436
+ return typeof arg === 'object' && arg !== null && 'getExperienceSelectionMiddleware' in arg && typeof arg.getExperienceSelectionMiddleware === 'function';
437
+ };
438
+
439
+ const selectPluginsHavingExperienceSelectionMiddleware = plugins => {
440
+ const filteredPlugins = [];
441
+ for (const plugin of plugins) {
442
+ if (hasExperienceSelectionMiddleware(plugin)) {
443
+ filteredPlugins.push(plugin);
444
+ }
445
+ }
446
+ return filteredPlugins;
447
+ };
448
+
449
+ const createPassThroughMiddleware = () => {
450
+ return ({
451
+ experience,
452
+ variant,
453
+ variantIndex
454
+ }) => {
455
+ return {
456
+ experience,
457
+ variant,
458
+ variantIndex
459
+ };
460
+ };
461
+ };
462
+ const makeExperienceSelectMiddleware = ({
463
+ plugins,
464
+ onChange,
465
+ experiences,
466
+ baseline,
467
+ profile
468
+ }) => {
469
+ let removeChangeListeners = [];
470
+ const pluginsHavingChangeEmitters = selectPluginsHavingOnChangeEmitter(plugins);
471
+ const prepareMiddleware = () => {
472
+ if (profile === null) {
473
+ return createPassThroughMiddleware();
474
+ }
475
+ const pluginsWithMiddleware = selectPluginsHavingExperienceSelectionMiddleware(plugins);
476
+ const middlewareFunctions = pluginsWithMiddleware.map(plugin => plugin.getExperienceSelectionMiddleware({
477
+ experiences,
478
+ baseline
479
+ }));
480
+ return experience_jsShared.pipe(...middlewareFunctions);
481
+ };
482
+ const middleware = prepareMiddleware();
483
+ const addListeners = () => {
484
+ removeChangeListeners = pluginsHavingChangeEmitters.map(plugin => {
485
+ const listener = () => {
486
+ onChange(middleware);
487
+ };
488
+ return plugin.onChangeEmitter.addListener(listener);
489
+ });
490
+ };
491
+ const removeListeners = () => {
492
+ removeChangeListeners.forEach(listener => listener());
493
+ };
494
+ return {
495
+ addListeners,
496
+ removeListeners,
497
+ middleware
498
+ };
499
+ };
500
+
501
+ class EventBuilder {
502
+ constructor(buildRequestContext) {
503
+ this.buildRequestContext = buildRequestContext || buildClientNinetailedRequestContext;
504
+ }
505
+ page(properties, data) {
506
+ return experience_jsShared.buildPageEvent(Object.assign(Object.assign({
507
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || uuid.v4()
508
+ }, data), {
509
+ timestamp: Date.now(),
510
+ properties: properties || {},
511
+ ctx: this.buildRequestContext()
512
+ }));
513
+ }
514
+ track(event, properties, data) {
515
+ return experience_jsShared.buildTrackEvent(Object.assign(Object.assign({
516
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || uuid.v4(),
517
+ timestamp: Date.now()
518
+ }, data), {
519
+ event,
520
+ properties: properties || {},
521
+ ctx: this.buildRequestContext()
522
+ }));
523
+ }
524
+ identify(userId, traits, data) {
525
+ return experience_jsShared.buildIdentifyEvent(Object.assign(Object.assign({
526
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || uuid.v4(),
527
+ timestamp: Date.now()
528
+ }, data), {
529
+ traits: traits || {},
530
+ userId: userId || '',
531
+ ctx: this.buildRequestContext()
532
+ }));
533
+ }
534
+ component(componentId, experienceId, variantIndex, data) {
535
+ return experience_jsShared.buildComponentViewEvent(Object.assign(Object.assign({
536
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || uuid.v4(),
537
+ timestamp: Date.now()
538
+ }, data), {
539
+ componentId,
540
+ experienceId: experienceId || '',
541
+ variantIndex: variantIndex || 0,
542
+ ctx: this.buildRequestContext()
543
+ }));
544
+ }
545
+ }
546
+
547
+ const buildOverrideMiddleware = experienceSelectionMiddleware => _a => {
548
+ var {
549
+ experience: originalExperience,
550
+ variant: originalVariant,
551
+ variantIndex: originalVariantIndex
552
+ } = _a,
553
+ other = __rest(_a, ["experience", "variant", "variantIndex"]);
554
+ const {
555
+ experience,
556
+ variant,
557
+ variantIndex
558
+ } = experienceSelectionMiddleware({
559
+ experience: originalExperience,
560
+ variant: originalVariant,
561
+ variantIndex: originalVariantIndex
562
+ });
563
+ return Object.assign(Object.assign({}, other), {
564
+ audience: (experience === null || experience === void 0 ? void 0 : experience.audience) ? experience.audience : null,
565
+ experience,
566
+ variant,
567
+ variantIndex
568
+ });
569
+ };
371
570
  class Ninetailed {
372
571
  constructor(ninetailedApiClientInstanceOrOptions, {
373
572
  plugins,
@@ -379,7 +578,8 @@ class Ninetailed {
379
578
  buildClientContext,
380
579
  onInitProfileId,
381
580
  componentViewTrackingThreshold = 2000,
382
- storageImpl
581
+ storageImpl,
582
+ useClientSideEvaluation = false
383
583
  } = {}) {
384
584
  this.isInitialized = false;
385
585
  this.page = (data, options) => __awaiter(this, void 0, void 0, function* () {
@@ -416,6 +616,78 @@ class Ninetailed {
416
616
  throw error;
417
617
  }
418
618
  });
619
+ this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
620
+ try {
621
+ const result = experience_jsShared.Traits.default({}).safeParse(traits);
622
+ if (!result.success) {
623
+ throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
624
+ }
625
+ yield this.waitUntilInitialized();
626
+ yield this.instance.identify(uid && uid.toString() !== '' ? uid.toString() : EMPTY_MERGE_ID, result.data, this.buildOptions(options));
627
+ return this.ninetailedCorePlugin.flush();
628
+ } catch (error) {
629
+ experience_jsShared.logger.error(error);
630
+ if (error instanceof RangeError) {
631
+ throw new Error(`[Validation Error] "identify" was called with invalid params. Could not validate due to "RangeError: Maximum call stack size exceeded". This can be caused by passing a cyclic data structure as a parameter. Refrain from passing a cyclic data structure or sanitize it beforehand.`);
632
+ }
633
+ throw error;
634
+ }
635
+ });
636
+ this.batch = events => __awaiter(this, void 0, void 0, function* () {
637
+ try {
638
+ yield this.waitUntilInitialized();
639
+ const promises = events.map(event => {
640
+ if (experience_jsShared.isPageViewEvent(event)) {
641
+ return this.instance.page(event.properties);
642
+ }
643
+ if (experience_jsShared.isTrackEvent(event)) {
644
+ return this.instance.track(event.event, event.properties);
645
+ }
646
+ if (experience_jsShared.isIdentifyEvent(event)) {
647
+ return this.instance.identify(event.userId || EMPTY_MERGE_ID, event.traits);
648
+ }
649
+ if (experience_jsShared.isComponentViewEvent(event)) {
650
+ return this.instance.dispatch({
651
+ experienceId: event.experienceId,
652
+ componentId: event.componentId,
653
+ variantIndex: event.variantIndex,
654
+ type: HAS_SEEN_STICKY_COMPONENT
655
+ });
656
+ }
657
+ return Promise.resolve();
658
+ });
659
+ yield Promise.all(promises);
660
+ return this.ninetailedCorePlugin.flush();
661
+ } catch (error) {
662
+ experience_jsShared.logger.error(error);
663
+ if (error instanceof RangeError) {
664
+ throw new Error(`[Validation Error] "batch" was called with invalid params. Could not validate due to "RangeError: Maximum call stack size exceeded". This can be caused by passing a cyclic data structure as a parameter. Refrain from passing a cyclic data structure or sanitize it beforehand.`);
665
+ }
666
+ throw error;
667
+ }
668
+ });
669
+ this.trackStickyComponentView = ({
670
+ experienceId,
671
+ componentId,
672
+ variantIndex
673
+ }) => __awaiter(this, void 0, void 0, function* () {
674
+ try {
675
+ yield this.waitUntilInitialized();
676
+ yield this.instance.dispatch({
677
+ experienceId,
678
+ componentId,
679
+ variantIndex,
680
+ type: HAS_SEEN_STICKY_COMPONENT
681
+ });
682
+ return this.ninetailedCorePlugin.flush();
683
+ } catch (error) {
684
+ experience_jsShared.logger.error(error);
685
+ if (error instanceof RangeError) {
686
+ throw new Error(`[Validation Error] "trackStickyComponentView" was called with invalid params. Could not validate due to "RangeError: Maximum call stack size exceeded". This can be caused by passing a cyclic data structure as a parameter. Refrain from passing a cyclic data structure or sanitize it beforehand.`);
687
+ }
688
+ throw error;
689
+ }
690
+ });
419
691
  /**
420
692
  * @deprecated The legacy datamodel is not recommended anymore
421
693
  * Will be removed in the next version of the SDK
@@ -459,23 +731,6 @@ class Ninetailed {
459
731
  }, payload));
460
732
  }
461
733
  };
462
- this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
463
- try {
464
- const result = experience_jsShared.Traits.default({}).safeParse(traits);
465
- if (!result.success) {
466
- throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
467
- }
468
- yield this.waitUntilInitialized();
469
- yield this.instance.identify(uid && uid.toString() !== '' ? uid.toString() : EMPTY_MERGE_ID, result.data, this.buildOptions(options));
470
- return this.ninetailedCorePlugin.flush();
471
- } catch (error) {
472
- experience_jsShared.logger.error(error);
473
- if (error instanceof RangeError) {
474
- throw new Error(`[Validation Error] "identify" was called with invalid params. Could not validate due to "RangeError: Maximum call stack size exceeded". This can be caused by passing a cyclic data structure as a parameter. Refrain from passing a cyclic data structure or sanitize it beforehand.`);
475
- }
476
- throw error;
477
- }
478
- });
479
734
  this.reset = () => __awaiter(this, void 0, void 0, function* () {
480
735
  yield this.waitUntilInitialized();
481
736
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -510,6 +765,165 @@ class Ninetailed {
510
765
  }
511
766
  });
512
767
  };
768
+ this.onSelectVariant = ({
769
+ baseline,
770
+ experiences
771
+ }, cb) => {
772
+ let middlewareChangeListeners = [];
773
+ let state = null;
774
+ const removeMiddlewareChangeListeners = () => {
775
+ middlewareChangeListeners.forEach(removeListener => removeListener());
776
+ middlewareChangeListeners = [];
777
+ };
778
+ const setSelectedVariant = newState => {
779
+ state = newState;
780
+ cb(state);
781
+ };
782
+ const removeProfileChangeListener = this.onProfileChange(profileState => {
783
+ const {
784
+ addListeners,
785
+ removeListeners,
786
+ middleware: experienceSelectionMiddleware
787
+ } = makeExperienceSelectMiddleware({
788
+ plugins: this.plugins,
789
+ experiences,
790
+ baseline,
791
+ profile: profileState.profile,
792
+ onChange: middleware => {
793
+ const overrideResult = buildOverrideMiddleware(middleware);
794
+ if (state !== null) {
795
+ setSelectedVariant(overrideResult(state));
796
+ }
797
+ }
798
+ });
799
+ addListeners();
800
+ middlewareChangeListeners.push(removeListeners);
801
+ const overrideResult = buildOverrideMiddleware(experienceSelectionMiddleware);
802
+ const hasVariants = experiences.map(experience => experience_jsShared.selectHasVariants(experience, baseline)).reduce((acc, curr) => acc || curr, false);
803
+ const baseReturn = Object.assign(Object.assign({}, profileState), {
804
+ hasVariants,
805
+ baseline
806
+ });
807
+ const emptyReturn = Object.assign(Object.assign({}, baseReturn), {
808
+ experience: null,
809
+ variant: baseline,
810
+ variantIndex: 0,
811
+ audience: null,
812
+ isPersonalized: false,
813
+ profile: null,
814
+ error: null
815
+ });
816
+ if (profileState.status === 'loading') {
817
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
818
+ loading: true,
819
+ status: 'loading'
820
+ })));
821
+ return;
822
+ }
823
+ if (profileState.status === 'error') {
824
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
825
+ loading: false,
826
+ status: 'error',
827
+ error: profileState.error
828
+ })));
829
+ return;
830
+ }
831
+ const {
832
+ profile,
833
+ experiences: selectedExperiences
834
+ } = profileState;
835
+ if (!profile || !selectedExperiences) {
836
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
837
+ loading: false,
838
+ status: 'error',
839
+ error: new Error('No Profile or Selected Experiences were returned by the API')
840
+ })));
841
+ return;
842
+ }
843
+ if (this.useClientSideEvaluation) {
844
+ const _experience = experience_jsShared.selectExperience({
845
+ experiences,
846
+ profile
847
+ });
848
+ if (!_experience) {
849
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
850
+ loading: false,
851
+ status: 'success',
852
+ profile
853
+ })));
854
+ return;
855
+ }
856
+ const {
857
+ variant: _variant,
858
+ index
859
+ } = experience_jsShared.selectVariant({
860
+ baseline,
861
+ experience: _experience,
862
+ profile
863
+ });
864
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, baseReturn), {
865
+ status: 'success',
866
+ loading: false,
867
+ error: null,
868
+ experience: _experience,
869
+ variant: _variant,
870
+ variantIndex: index,
871
+ audience: _experience.audience ? _experience.audience : null,
872
+ profile,
873
+ isPersonalized: true
874
+ })));
875
+ return;
876
+ }
877
+ const experience = experiences.find(experience => selectedExperiences.some(selectedExperience => selectedExperience.experienceId === experience.id));
878
+ const selectedExperience = selectedExperiences.find(({
879
+ experienceId
880
+ }) => experienceId === (experience === null || experience === void 0 ? void 0 : experience.id));
881
+ if (!experience || !selectedExperience) {
882
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
883
+ loading: false,
884
+ status: 'success',
885
+ profile
886
+ })));
887
+ return;
888
+ }
889
+ const baselineVariants = experience_jsShared.selectBaselineWithVariants(experience, baseline);
890
+ if (!baselineVariants) {
891
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
892
+ loading: false,
893
+ status: 'success',
894
+ profile
895
+ })));
896
+ return;
897
+ }
898
+ const {
899
+ variants
900
+ } = baselineVariants;
901
+ const variant = variants[selectedExperience.variantIndex - 1];
902
+ if (!variant) {
903
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
904
+ loading: false,
905
+ status: 'success',
906
+ profile
907
+ })));
908
+ return;
909
+ }
910
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, baseReturn), {
911
+ status: 'success',
912
+ loading: false,
913
+ error: null,
914
+ experience,
915
+ variant,
916
+ variantIndex: selectedExperience.variantIndex,
917
+ audience: experience.audience ? experience.audience : null,
918
+ profile,
919
+ isPersonalized: true
920
+ })));
921
+ });
922
+ return () => {
923
+ removeProfileChangeListener();
924
+ removeMiddlewareChangeListeners();
925
+ };
926
+ };
513
927
  this.onIsInitialized = onIsInitialized => {
514
928
  if (typeof onIsInitialized === 'function') {
515
929
  if (this.isInitialized) {
@@ -540,6 +954,7 @@ class Ninetailed {
540
954
  }
541
955
  });
542
956
  };
957
+ this.useClientSideEvaluation = useClientSideEvaluation;
543
958
  if (ninetailedApiClientInstanceOrOptions instanceof experience_jsShared.NinetailedApiClient) {
544
959
  this.apiClient = ninetailedApiClientInstanceOrOptions;
545
960
  } else {
@@ -579,6 +994,7 @@ class Ninetailed {
579
994
  if (typeof onError === 'function') {
580
995
  experience_jsShared.logger.addSink(new experience_jsShared.OnErrorLogSink(onError));
581
996
  }
997
+ this.eventBuilder = new EventBuilder(buildClientContext);
582
998
  this.logger = experience_jsShared.logger;
583
999
  this.ninetailedCorePlugin = ninetailedCorePlugin({
584
1000
  apiClient: this.apiClient,
@@ -763,120 +1179,6 @@ const ElementSeenPayloadSchema = zod.z.object({
763
1179
  variantIndex: zod.z.number()
764
1180
  });
765
1181
 
766
- const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
767
- return encodedExperienceVariantsMap.split(',').map(experienceIdWithVariant => {
768
- const [experienceId, _variantIndex] = experienceIdWithVariant.split('=');
769
- const variantIndex = parseInt(_variantIndex);
770
- if (!experienceId || !variantIndex) {
771
- return null;
772
- }
773
- return {
774
- experienceId,
775
- variantIndex
776
- };
777
- }).filter(x => !!x).reduce((acc, curr) => Object.assign(Object.assign({}, acc), {
778
- [curr.experienceId]: curr.variantIndex
779
- }), {});
780
- };
781
-
782
- class OnChangeEmitter {
783
- constructor() {
784
- this.onChangeListeners = [];
785
- }
786
- addListener(listener) {
787
- this.onChangeListeners.push(listener);
788
- return () => {
789
- this.removeOnChangeListener(listener);
790
- };
791
- }
792
- invokeListeners() {
793
- this.onChangeListeners.forEach(listener => listener());
794
- }
795
- removeOnChangeListener(listener) {
796
- this.onChangeListeners = this.onChangeListeners.filter(l => l !== listener);
797
- }
798
- }
799
-
800
- const hasOnChangeEmitter = arg => {
801
- return typeof arg === 'object' && arg !== null && 'onChangeEmitter' in arg && typeof arg.onChangeEmitter === 'object' && arg.onChangeEmitter !== null && arg.onChangeEmitter.constructor === OnChangeEmitter;
802
- };
803
-
804
- const selectPluginsHavingOnChangeEmitter = plugins => {
805
- const filteredPlugins = [];
806
- for (const plugin of plugins) {
807
- if (hasOnChangeEmitter(plugin)) {
808
- filteredPlugins.push(plugin);
809
- }
810
- }
811
- return filteredPlugins;
812
- };
813
-
814
- const hasExperienceSelectionMiddleware = arg => {
815
- return typeof arg === 'object' && arg !== null && 'getExperienceSelectionMiddleware' in arg && typeof arg.getExperienceSelectionMiddleware === 'function';
816
- };
817
-
818
- const selectPluginsHavingExperienceSelectionMiddleware = plugins => {
819
- const filteredPlugins = [];
820
- for (const plugin of plugins) {
821
- if (hasExperienceSelectionMiddleware(plugin)) {
822
- filteredPlugins.push(plugin);
823
- }
824
- }
825
- return filteredPlugins;
826
- };
827
-
828
- const createPassThroughMiddleware = () => {
829
- return ({
830
- experience,
831
- variant,
832
- variantIndex
833
- }) => {
834
- return {
835
- experience,
836
- variant,
837
- variantIndex
838
- };
839
- };
840
- };
841
- const makeExperienceSelectMiddleware = ({
842
- plugins,
843
- onChange,
844
- experiences,
845
- baseline,
846
- profile
847
- }) => {
848
- let removeChangeListeners = [];
849
- const pluginsHavingChangeEmitters = selectPluginsHavingOnChangeEmitter(plugins);
850
- const prepareMiddleware = () => {
851
- if (profile === null) {
852
- return createPassThroughMiddleware();
853
- }
854
- const pluginsWithMiddleware = selectPluginsHavingExperienceSelectionMiddleware(plugins);
855
- const middlewareFunctions = pluginsWithMiddleware.map(plugin => plugin.getExperienceSelectionMiddleware({
856
- experiences,
857
- baseline
858
- }));
859
- return experience_jsShared.pipe(...middlewareFunctions);
860
- };
861
- const addListeners = () => {
862
- removeChangeListeners = pluginsHavingChangeEmitters.map(plugin => {
863
- const listener = () => {
864
- onChange();
865
- };
866
- return plugin.onChangeEmitter.addListener(listener);
867
- });
868
- };
869
- const removeListeners = () => {
870
- removeChangeListeners.forEach(listener => listener());
871
- };
872
- const middleware = prepareMiddleware();
873
- return {
874
- addListeners,
875
- removeListeners,
876
- middleware
877
- };
878
- };
879
-
880
1182
  Object.defineProperty(exports, 'EXPERIENCE_TRAIT_PREFIX', {
881
1183
  enumerable: true,
882
1184
  get: function () { return experience_jsShared.EXPERIENCE_TRAIT_PREFIX; }
@@ -923,6 +1225,7 @@ exports.EXPERIENCES_FALLBACK_CACHE = EXPERIENCES_FALLBACK_CACHE;
923
1225
  exports.ElementSeenPayloadSchema = ElementSeenPayloadSchema;
924
1226
  exports.HAS_SEEN_COMPONENT = HAS_SEEN_COMPONENT;
925
1227
  exports.HAS_SEEN_ELEMENT = HAS_SEEN_ELEMENT;
1228
+ exports.HAS_SEEN_STICKY_COMPONENT = HAS_SEEN_STICKY_COMPONENT;
926
1229
  exports.LEGACY_ANONYMOUS_ID = LEGACY_ANONYMOUS_ID;
927
1230
  exports.Ninetailed = Ninetailed;
928
1231
  exports.NinetailedPlugin = NinetailedPlugin;