@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.js CHANGED
@@ -1,6 +1,7 @@
1
- import { FEATURES, logger, ConsoleLogSink, buildPageEvent, buildTrackEvent, buildIdentifyEvent, unionBy, NinetailedApiClient, OnLogLogSink, OnErrorLogSink, PageviewProperties, Properties, Traits, pipe } from '@ninetailed/experience.js-shared';
1
+ import { FEATURES, logger, ConsoleLogSink, buildPageEvent, buildTrackEvent, buildIdentifyEvent, buildComponentViewEvent, unionBy, pipe, selectHasVariants, selectExperience, selectVariant as selectVariant$1, selectBaselineWithVariants, NinetailedApiClient, OnLogLogSink, OnErrorLogSink, PageviewProperties, Properties, Traits, isPageViewEvent, isTrackEvent, isIdentifyEvent, isComponentViewEvent } from '@ninetailed/experience.js-shared';
2
2
  export { EXPERIENCE_TRAIT_PREFIX, isExperienceMatch, selectActiveExperiments, selectDistribution, selectExperience, selectBaselineWithVariants as selectExperienceBaselineWithVariants, selectVariant as selectExperienceVariant, selectVariants as selectExperienceVariants, selectHasVariants as selectHasExperienceVariants } from '@ninetailed/experience.js-shared';
3
3
  import Analytics from 'analytics';
4
+ import { v4 } from 'uuid';
4
5
  import { z } from 'zod';
5
6
 
6
7
  const HAS_SEEN_COMPONENT = 'has_seen_component';
@@ -8,6 +9,7 @@ const HAS_SEEN_ELEMENT = 'has_seen_element';
8
9
  const COMPONENT = 'component';
9
10
  const COMPONENT_START = 'componentStart';
10
11
  const PAGE_HIDDEN = 'page_hidden';
12
+ const HAS_SEEN_STICKY_COMPONENT = 'sticky_component_view';
11
13
 
12
14
  /******************************************************************************
13
15
  Copyright (c) Microsoft Corporation.
@@ -265,6 +267,20 @@ const ninetailedCorePlugin = ({
265
267
  ctx
266
268
  }));
267
269
  }),
270
+ [HAS_SEEN_STICKY_COMPONENT]: ({
271
+ payload
272
+ }) => __awaiter(void 0, void 0, void 0, function* () {
273
+ logger.info('Sending Sticky Components event.');
274
+ const ctx = buildContext();
275
+ return enqueueEvent(buildComponentViewEvent({
276
+ messageId: payload.meta.rid,
277
+ timestamp: payload.meta.ts,
278
+ componentId: payload.componentId,
279
+ experienceId: payload.experienceId,
280
+ variantIndex: payload.variantIndex,
281
+ ctx
282
+ }));
283
+ }),
268
284
  setItemStart: ({
269
285
  abort,
270
286
  payload
@@ -361,6 +377,189 @@ const isInterestedInHiddenPage = arg => {
361
377
  return typeof arg === 'object' && arg !== null && PAGE_HIDDEN in arg && typeof arg[PAGE_HIDDEN] === 'function';
362
378
  };
363
379
 
380
+ const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
381
+ return encodedExperienceVariantsMap.split(',').map(experienceIdWithVariant => {
382
+ const [experienceId, _variantIndex] = experienceIdWithVariant.split('=');
383
+ const variantIndex = parseInt(_variantIndex);
384
+ if (!experienceId || !variantIndex) {
385
+ return null;
386
+ }
387
+ return {
388
+ experienceId,
389
+ variantIndex
390
+ };
391
+ }).filter(x => !!x).reduce((acc, curr) => Object.assign(Object.assign({}, acc), {
392
+ [curr.experienceId]: curr.variantIndex
393
+ }), {});
394
+ };
395
+
396
+ class OnChangeEmitter {
397
+ constructor() {
398
+ this.onChangeListeners = [];
399
+ }
400
+ addListener(listener) {
401
+ this.onChangeListeners.push(listener);
402
+ return () => {
403
+ this.removeOnChangeListener(listener);
404
+ };
405
+ }
406
+ invokeListeners() {
407
+ this.onChangeListeners.forEach(listener => listener());
408
+ }
409
+ removeOnChangeListener(listener) {
410
+ this.onChangeListeners = this.onChangeListeners.filter(l => l !== listener);
411
+ }
412
+ }
413
+
414
+ const hasOnChangeEmitter = arg => {
415
+ return typeof arg === 'object' && arg !== null && 'onChangeEmitter' in arg && typeof arg.onChangeEmitter === 'object' && arg.onChangeEmitter !== null && arg.onChangeEmitter.constructor === OnChangeEmitter;
416
+ };
417
+
418
+ const selectPluginsHavingOnChangeEmitter = plugins => {
419
+ const filteredPlugins = [];
420
+ for (const plugin of plugins) {
421
+ if (hasOnChangeEmitter(plugin)) {
422
+ filteredPlugins.push(plugin);
423
+ }
424
+ }
425
+ return filteredPlugins;
426
+ };
427
+
428
+ const hasExperienceSelectionMiddleware = arg => {
429
+ return typeof arg === 'object' && arg !== null && 'getExperienceSelectionMiddleware' in arg && typeof arg.getExperienceSelectionMiddleware === 'function';
430
+ };
431
+
432
+ const selectPluginsHavingExperienceSelectionMiddleware = plugins => {
433
+ const filteredPlugins = [];
434
+ for (const plugin of plugins) {
435
+ if (hasExperienceSelectionMiddleware(plugin)) {
436
+ filteredPlugins.push(plugin);
437
+ }
438
+ }
439
+ return filteredPlugins;
440
+ };
441
+
442
+ const createPassThroughMiddleware = () => {
443
+ return ({
444
+ experience,
445
+ variant,
446
+ variantIndex
447
+ }) => {
448
+ return {
449
+ experience,
450
+ variant,
451
+ variantIndex
452
+ };
453
+ };
454
+ };
455
+ const makeExperienceSelectMiddleware = ({
456
+ plugins,
457
+ onChange,
458
+ experiences,
459
+ baseline,
460
+ profile
461
+ }) => {
462
+ let removeChangeListeners = [];
463
+ const pluginsHavingChangeEmitters = selectPluginsHavingOnChangeEmitter(plugins);
464
+ const prepareMiddleware = () => {
465
+ if (profile === null) {
466
+ return createPassThroughMiddleware();
467
+ }
468
+ const pluginsWithMiddleware = selectPluginsHavingExperienceSelectionMiddleware(plugins);
469
+ const middlewareFunctions = pluginsWithMiddleware.map(plugin => plugin.getExperienceSelectionMiddleware({
470
+ experiences,
471
+ baseline
472
+ }));
473
+ return pipe(...middlewareFunctions);
474
+ };
475
+ const middleware = prepareMiddleware();
476
+ const addListeners = () => {
477
+ removeChangeListeners = pluginsHavingChangeEmitters.map(plugin => {
478
+ const listener = () => {
479
+ onChange(middleware);
480
+ };
481
+ return plugin.onChangeEmitter.addListener(listener);
482
+ });
483
+ };
484
+ const removeListeners = () => {
485
+ removeChangeListeners.forEach(listener => listener());
486
+ };
487
+ return {
488
+ addListeners,
489
+ removeListeners,
490
+ middleware
491
+ };
492
+ };
493
+
494
+ class EventBuilder {
495
+ constructor(buildRequestContext) {
496
+ this.buildRequestContext = buildRequestContext || buildClientNinetailedRequestContext;
497
+ }
498
+ page(properties, data) {
499
+ return buildPageEvent(Object.assign(Object.assign({
500
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4()
501
+ }, data), {
502
+ timestamp: Date.now(),
503
+ properties: properties || {},
504
+ ctx: this.buildRequestContext()
505
+ }));
506
+ }
507
+ track(event, properties, data) {
508
+ return buildTrackEvent(Object.assign(Object.assign({
509
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4(),
510
+ timestamp: Date.now()
511
+ }, data), {
512
+ event,
513
+ properties: properties || {},
514
+ ctx: this.buildRequestContext()
515
+ }));
516
+ }
517
+ identify(userId, traits, data) {
518
+ return buildIdentifyEvent(Object.assign(Object.assign({
519
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4(),
520
+ timestamp: Date.now()
521
+ }, data), {
522
+ traits: traits || {},
523
+ userId: userId || '',
524
+ ctx: this.buildRequestContext()
525
+ }));
526
+ }
527
+ component(componentId, experienceId, variantIndex, data) {
528
+ return buildComponentViewEvent(Object.assign(Object.assign({
529
+ messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4(),
530
+ timestamp: Date.now()
531
+ }, data), {
532
+ componentId,
533
+ experienceId: experienceId || '',
534
+ variantIndex: variantIndex || 0,
535
+ ctx: this.buildRequestContext()
536
+ }));
537
+ }
538
+ }
539
+
540
+ const buildOverrideMiddleware = experienceSelectionMiddleware => _a => {
541
+ var {
542
+ experience: originalExperience,
543
+ variant: originalVariant,
544
+ variantIndex: originalVariantIndex
545
+ } = _a,
546
+ other = __rest(_a, ["experience", "variant", "variantIndex"]);
547
+ const {
548
+ experience,
549
+ variant,
550
+ variantIndex
551
+ } = experienceSelectionMiddleware({
552
+ experience: originalExperience,
553
+ variant: originalVariant,
554
+ variantIndex: originalVariantIndex
555
+ });
556
+ return Object.assign(Object.assign({}, other), {
557
+ audience: (experience === null || experience === void 0 ? void 0 : experience.audience) ? experience.audience : null,
558
+ experience,
559
+ variant,
560
+ variantIndex
561
+ });
562
+ };
364
563
  class Ninetailed {
365
564
  constructor(ninetailedApiClientInstanceOrOptions, {
366
565
  plugins,
@@ -372,7 +571,8 @@ class Ninetailed {
372
571
  buildClientContext,
373
572
  onInitProfileId,
374
573
  componentViewTrackingThreshold = 2000,
375
- storageImpl
574
+ storageImpl,
575
+ useClientSideEvaluation = false
376
576
  } = {}) {
377
577
  this.isInitialized = false;
378
578
  this.page = (data, options) => __awaiter(this, void 0, void 0, function* () {
@@ -409,6 +609,78 @@ class Ninetailed {
409
609
  throw error;
410
610
  }
411
611
  });
612
+ this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
613
+ try {
614
+ const result = Traits.default({}).safeParse(traits);
615
+ if (!result.success) {
616
+ throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
617
+ }
618
+ yield this.waitUntilInitialized();
619
+ yield this.instance.identify(uid && uid.toString() !== '' ? uid.toString() : EMPTY_MERGE_ID, result.data, this.buildOptions(options));
620
+ return this.ninetailedCorePlugin.flush();
621
+ } catch (error) {
622
+ logger.error(error);
623
+ if (error instanceof RangeError) {
624
+ 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.`);
625
+ }
626
+ throw error;
627
+ }
628
+ });
629
+ this.batch = events => __awaiter(this, void 0, void 0, function* () {
630
+ try {
631
+ yield this.waitUntilInitialized();
632
+ const promises = events.map(event => {
633
+ if (isPageViewEvent(event)) {
634
+ return this.instance.page(event.properties);
635
+ }
636
+ if (isTrackEvent(event)) {
637
+ return this.instance.track(event.event, event.properties);
638
+ }
639
+ if (isIdentifyEvent(event)) {
640
+ return this.instance.identify(event.userId || EMPTY_MERGE_ID, event.traits);
641
+ }
642
+ if (isComponentViewEvent(event)) {
643
+ return this.instance.dispatch({
644
+ experienceId: event.experienceId,
645
+ componentId: event.componentId,
646
+ variantIndex: event.variantIndex,
647
+ type: HAS_SEEN_STICKY_COMPONENT
648
+ });
649
+ }
650
+ return Promise.resolve();
651
+ });
652
+ yield Promise.all(promises);
653
+ return this.ninetailedCorePlugin.flush();
654
+ } catch (error) {
655
+ logger.error(error);
656
+ if (error instanceof RangeError) {
657
+ 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.`);
658
+ }
659
+ throw error;
660
+ }
661
+ });
662
+ this.trackStickyComponentView = ({
663
+ experienceId,
664
+ componentId,
665
+ variantIndex
666
+ }) => __awaiter(this, void 0, void 0, function* () {
667
+ try {
668
+ yield this.waitUntilInitialized();
669
+ yield this.instance.dispatch({
670
+ experienceId,
671
+ componentId,
672
+ variantIndex,
673
+ type: HAS_SEEN_STICKY_COMPONENT
674
+ });
675
+ return this.ninetailedCorePlugin.flush();
676
+ } catch (error) {
677
+ logger.error(error);
678
+ if (error instanceof RangeError) {
679
+ 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.`);
680
+ }
681
+ throw error;
682
+ }
683
+ });
412
684
  /**
413
685
  * @deprecated The legacy datamodel is not recommended anymore
414
686
  * Will be removed in the next version of the SDK
@@ -452,23 +724,6 @@ class Ninetailed {
452
724
  }, payload));
453
725
  }
454
726
  };
455
- this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
456
- try {
457
- const result = Traits.default({}).safeParse(traits);
458
- if (!result.success) {
459
- throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
460
- }
461
- yield this.waitUntilInitialized();
462
- yield this.instance.identify(uid && uid.toString() !== '' ? uid.toString() : EMPTY_MERGE_ID, result.data, this.buildOptions(options));
463
- return this.ninetailedCorePlugin.flush();
464
- } catch (error) {
465
- logger.error(error);
466
- if (error instanceof RangeError) {
467
- 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.`);
468
- }
469
- throw error;
470
- }
471
- });
472
727
  this.reset = () => __awaiter(this, void 0, void 0, function* () {
473
728
  yield this.waitUntilInitialized();
474
729
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -503,6 +758,165 @@ class Ninetailed {
503
758
  }
504
759
  });
505
760
  };
761
+ this.onSelectVariant = ({
762
+ baseline,
763
+ experiences
764
+ }, cb) => {
765
+ let middlewareChangeListeners = [];
766
+ let state = null;
767
+ const removeMiddlewareChangeListeners = () => {
768
+ middlewareChangeListeners.forEach(removeListener => removeListener());
769
+ middlewareChangeListeners = [];
770
+ };
771
+ const setSelectedVariant = newState => {
772
+ state = newState;
773
+ cb(state);
774
+ };
775
+ const removeProfileChangeListener = this.onProfileChange(profileState => {
776
+ const {
777
+ addListeners,
778
+ removeListeners,
779
+ middleware: experienceSelectionMiddleware
780
+ } = makeExperienceSelectMiddleware({
781
+ plugins: this.plugins,
782
+ experiences,
783
+ baseline,
784
+ profile: profileState.profile,
785
+ onChange: middleware => {
786
+ const overrideResult = buildOverrideMiddleware(middleware);
787
+ if (state !== null) {
788
+ setSelectedVariant(overrideResult(state));
789
+ }
790
+ }
791
+ });
792
+ addListeners();
793
+ middlewareChangeListeners.push(removeListeners);
794
+ const overrideResult = buildOverrideMiddleware(experienceSelectionMiddleware);
795
+ const hasVariants = experiences.map(experience => selectHasVariants(experience, baseline)).reduce((acc, curr) => acc || curr, false);
796
+ const baseReturn = Object.assign(Object.assign({}, profileState), {
797
+ hasVariants,
798
+ baseline
799
+ });
800
+ const emptyReturn = Object.assign(Object.assign({}, baseReturn), {
801
+ experience: null,
802
+ variant: baseline,
803
+ variantIndex: 0,
804
+ audience: null,
805
+ isPersonalized: false,
806
+ profile: null,
807
+ error: null
808
+ });
809
+ if (profileState.status === 'loading') {
810
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
811
+ loading: true,
812
+ status: 'loading'
813
+ })));
814
+ return;
815
+ }
816
+ if (profileState.status === 'error') {
817
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
818
+ loading: false,
819
+ status: 'error',
820
+ error: profileState.error
821
+ })));
822
+ return;
823
+ }
824
+ const {
825
+ profile,
826
+ experiences: selectedExperiences
827
+ } = profileState;
828
+ if (!profile || !selectedExperiences) {
829
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
830
+ loading: false,
831
+ status: 'error',
832
+ error: new Error('No Profile or Selected Experiences were returned by the API')
833
+ })));
834
+ return;
835
+ }
836
+ if (this.useClientSideEvaluation) {
837
+ const _experience = selectExperience({
838
+ experiences,
839
+ profile
840
+ });
841
+ if (!_experience) {
842
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
843
+ loading: false,
844
+ status: 'success',
845
+ profile
846
+ })));
847
+ return;
848
+ }
849
+ const {
850
+ variant: _variant,
851
+ index
852
+ } = selectVariant$1({
853
+ baseline,
854
+ experience: _experience,
855
+ profile
856
+ });
857
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, baseReturn), {
858
+ status: 'success',
859
+ loading: false,
860
+ error: null,
861
+ experience: _experience,
862
+ variant: _variant,
863
+ variantIndex: index,
864
+ audience: _experience.audience ? _experience.audience : null,
865
+ profile,
866
+ isPersonalized: true
867
+ })));
868
+ return;
869
+ }
870
+ const experience = experiences.find(experience => selectedExperiences.some(selectedExperience => selectedExperience.experienceId === experience.id));
871
+ const selectedExperience = selectedExperiences.find(({
872
+ experienceId
873
+ }) => experienceId === (experience === null || experience === void 0 ? void 0 : experience.id));
874
+ if (!experience || !selectedExperience) {
875
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
876
+ loading: false,
877
+ status: 'success',
878
+ profile
879
+ })));
880
+ return;
881
+ }
882
+ const baselineVariants = selectBaselineWithVariants(experience, baseline);
883
+ if (!baselineVariants) {
884
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
885
+ loading: false,
886
+ status: 'success',
887
+ profile
888
+ })));
889
+ return;
890
+ }
891
+ const {
892
+ variants
893
+ } = baselineVariants;
894
+ const variant = variants[selectedExperience.variantIndex - 1];
895
+ if (!variant) {
896
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
897
+ loading: false,
898
+ status: 'success',
899
+ profile
900
+ })));
901
+ return;
902
+ }
903
+ setSelectedVariant(overrideResult(Object.assign(Object.assign({}, baseReturn), {
904
+ status: 'success',
905
+ loading: false,
906
+ error: null,
907
+ experience,
908
+ variant,
909
+ variantIndex: selectedExperience.variantIndex,
910
+ audience: experience.audience ? experience.audience : null,
911
+ profile,
912
+ isPersonalized: true
913
+ })));
914
+ });
915
+ return () => {
916
+ removeProfileChangeListener();
917
+ removeMiddlewareChangeListeners();
918
+ };
919
+ };
506
920
  this.onIsInitialized = onIsInitialized => {
507
921
  if (typeof onIsInitialized === 'function') {
508
922
  if (this.isInitialized) {
@@ -533,6 +947,7 @@ class Ninetailed {
533
947
  }
534
948
  });
535
949
  };
950
+ this.useClientSideEvaluation = useClientSideEvaluation;
536
951
  if (ninetailedApiClientInstanceOrOptions instanceof NinetailedApiClient) {
537
952
  this.apiClient = ninetailedApiClientInstanceOrOptions;
538
953
  } else {
@@ -572,6 +987,7 @@ class Ninetailed {
572
987
  if (typeof onError === 'function') {
573
988
  logger.addSink(new OnErrorLogSink(onError));
574
989
  }
990
+ this.eventBuilder = new EventBuilder(buildClientContext);
575
991
  this.logger = logger;
576
992
  this.ninetailedCorePlugin = ninetailedCorePlugin({
577
993
  apiClient: this.apiClient,
@@ -756,118 +1172,4 @@ const ElementSeenPayloadSchema = z.object({
756
1172
  variantIndex: z.number()
757
1173
  });
758
1174
 
759
- const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
760
- return encodedExperienceVariantsMap.split(',').map(experienceIdWithVariant => {
761
- const [experienceId, _variantIndex] = experienceIdWithVariant.split('=');
762
- const variantIndex = parseInt(_variantIndex);
763
- if (!experienceId || !variantIndex) {
764
- return null;
765
- }
766
- return {
767
- experienceId,
768
- variantIndex
769
- };
770
- }).filter(x => !!x).reduce((acc, curr) => Object.assign(Object.assign({}, acc), {
771
- [curr.experienceId]: curr.variantIndex
772
- }), {});
773
- };
774
-
775
- class OnChangeEmitter {
776
- constructor() {
777
- this.onChangeListeners = [];
778
- }
779
- addListener(listener) {
780
- this.onChangeListeners.push(listener);
781
- return () => {
782
- this.removeOnChangeListener(listener);
783
- };
784
- }
785
- invokeListeners() {
786
- this.onChangeListeners.forEach(listener => listener());
787
- }
788
- removeOnChangeListener(listener) {
789
- this.onChangeListeners = this.onChangeListeners.filter(l => l !== listener);
790
- }
791
- }
792
-
793
- const hasOnChangeEmitter = arg => {
794
- return typeof arg === 'object' && arg !== null && 'onChangeEmitter' in arg && typeof arg.onChangeEmitter === 'object' && arg.onChangeEmitter !== null && arg.onChangeEmitter.constructor === OnChangeEmitter;
795
- };
796
-
797
- const selectPluginsHavingOnChangeEmitter = plugins => {
798
- const filteredPlugins = [];
799
- for (const plugin of plugins) {
800
- if (hasOnChangeEmitter(plugin)) {
801
- filteredPlugins.push(plugin);
802
- }
803
- }
804
- return filteredPlugins;
805
- };
806
-
807
- const hasExperienceSelectionMiddleware = arg => {
808
- return typeof arg === 'object' && arg !== null && 'getExperienceSelectionMiddleware' in arg && typeof arg.getExperienceSelectionMiddleware === 'function';
809
- };
810
-
811
- const selectPluginsHavingExperienceSelectionMiddleware = plugins => {
812
- const filteredPlugins = [];
813
- for (const plugin of plugins) {
814
- if (hasExperienceSelectionMiddleware(plugin)) {
815
- filteredPlugins.push(plugin);
816
- }
817
- }
818
- return filteredPlugins;
819
- };
820
-
821
- const createPassThroughMiddleware = () => {
822
- return ({
823
- experience,
824
- variant,
825
- variantIndex
826
- }) => {
827
- return {
828
- experience,
829
- variant,
830
- variantIndex
831
- };
832
- };
833
- };
834
- const makeExperienceSelectMiddleware = ({
835
- plugins,
836
- onChange,
837
- experiences,
838
- baseline,
839
- profile
840
- }) => {
841
- let removeChangeListeners = [];
842
- const pluginsHavingChangeEmitters = selectPluginsHavingOnChangeEmitter(plugins);
843
- const prepareMiddleware = () => {
844
- if (profile === null) {
845
- return createPassThroughMiddleware();
846
- }
847
- const pluginsWithMiddleware = selectPluginsHavingExperienceSelectionMiddleware(plugins);
848
- const middlewareFunctions = pluginsWithMiddleware.map(plugin => plugin.getExperienceSelectionMiddleware({
849
- experiences,
850
- baseline
851
- }));
852
- return pipe(...middlewareFunctions);
853
- };
854
- const addListeners = () => {
855
- removeChangeListeners = pluginsHavingChangeEmitters.map(plugin => {
856
- const listener = () => {
857
- onChange();
858
- };
859
- return plugin.onChangeEmitter.addListener(listener);
860
- });
861
- };
862
- const removeListeners = () => {
863
- removeChangeListeners.forEach(listener => listener());
864
- };
865
- const middleware = prepareMiddleware();
866
- return {
867
- addListeners,
868
- removeListeners,
869
- middleware
870
- };
871
- };
872
-
873
- export { ANONYMOUS_ID, COMPONENT, COMPONENT_START, CONSENT, DEBUG_FLAG, EMPTY_MERGE_ID, EXPERIENCES_FALLBACK_CACHE, ElementSeenPayloadSchema, HAS_SEEN_COMPONENT, HAS_SEEN_ELEMENT, LEGACY_ANONYMOUS_ID, Ninetailed, NinetailedPlugin, OnChangeEmitter, PAGE_HIDDEN, PLUGIN_NAME, PROFILE_CHANGE, PROFILE_FALLBACK_CACHE, PROFILE_RESET, SET_ENABLED_FEATURES, TrackComponentProperties, buildClientNinetailedRequestContext, decodeExperienceVariantsMap, makeExperienceSelectMiddleware, ninetailedCorePlugin, selectPluginsHavingExperienceSelectionMiddleware, selectPluginsHavingOnChangeEmitter, selectVariant };
1175
+ export { ANONYMOUS_ID, COMPONENT, COMPONENT_START, CONSENT, DEBUG_FLAG, EMPTY_MERGE_ID, EXPERIENCES_FALLBACK_CACHE, ElementSeenPayloadSchema, HAS_SEEN_COMPONENT, HAS_SEEN_ELEMENT, HAS_SEEN_STICKY_COMPONENT, LEGACY_ANONYMOUS_ID, Ninetailed, NinetailedPlugin, OnChangeEmitter, PAGE_HIDDEN, PLUGIN_NAME, PROFILE_CHANGE, PROFILE_FALLBACK_CACHE, PROFILE_RESET, SET_ENABLED_FEATURES, TrackComponentProperties, buildClientNinetailedRequestContext, decodeExperienceVariantsMap, makeExperienceSelectMiddleware, ninetailedCorePlugin, selectPluginsHavingExperienceSelectionMiddleware, selectPluginsHavingOnChangeEmitter, selectVariant };
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js",
3
- "version": "7.5.0-beta.9",
3
+ "version": "7.6.0-beta.1",
4
4
  "license": "BSL-1.1",
5
5
  "module": "./index.js",
6
6
  "main": "./index.cjs",
7
7
  "type": "module",
8
8
  "types": "./src/index.d.ts",
9
9
  "dependencies": {
10
- "@ninetailed/experience.js-shared": "7.5.0-beta.9",
10
+ "@ninetailed/experience.js-shared": "7.6.0-beta.1",
11
11
  "analytics": "0.8.1",
12
+ "uuid": "9.0.0",
12
13
  "zod": "3.21.4"
13
14
  },
14
15
  "peerDependencies": {}