@ninetailed/experience.js 7.6.0-beta.1 → 7.6.0-beta.3

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 (28) hide show
  1. package/index.cjs.d.ts +1 -0
  2. package/{index.cjs → index.cjs.js} +276 -244
  3. package/{index.js → index.esm.js} +411 -383
  4. package/package.json +13 -9
  5. package/src/index.d.ts +1 -1
  6. package/src/lib/ElementSeenObserver.d.ts +1 -1
  7. package/src/lib/Ninetailed.d.ts +4 -2
  8. package/src/lib/NinetailedCorePlugin/NinetailedCorePlugin.d.ts +69 -0
  9. package/src/lib/{ninetailedCorePlugin → NinetailedCorePlugin}/index.d.ts +1 -1
  10. package/src/lib/constants.d.ts +0 -2
  11. package/src/lib/experience/makeExperienceSelectMiddleware.d.ts +1 -1
  12. package/src/lib/guards/hasComponentViewTrackingThreshold.d.ts +3 -0
  13. package/src/lib/plugins/selectPluginsHavingExperienceSelectionMiddleware.d.ts +1 -1
  14. package/src/lib/plugins/selectPluginsHavingOnChangeEmitter.d.ts +1 -1
  15. package/src/lib/types/index.d.ts +2 -8
  16. package/src/lib/types/interfaces/HasComponentViewTrackingThreshold.d.ts +3 -0
  17. package/src/lib/types/interfaces/InterestedInHiddenPage.d.ts +1 -1
  18. package/src/lib/types/interfaces/InterestedInProfileChange.d.ts +1 -1
  19. package/src/lib/types/interfaces/InterestedInSeenElements.d.ts +1 -3
  20. package/src/lib/ninetailedCorePlugin/ninetailedCorePlugin.d.ts +0 -17
  21. package/src/lib/types/ElementSeenPayload.d.ts +0 -82
  22. package/src/lib/types/EventHandler.d.ts +0 -6
  23. package/src/lib/types/NinetailedPlugin.d.ts +0 -11
  24. package/src/lib/types/TrackingProperties.d.ts +0 -35
  25. /package/src/lib/{ninetailedCorePlugin → NinetailedCorePlugin}/Events/build-context.d.ts +0 -0
  26. /package/src/lib/{ninetailedCorePlugin → NinetailedCorePlugin}/Events/build-locale.d.ts +0 -0
  27. /package/src/lib/{ninetailedCorePlugin → NinetailedCorePlugin}/Events/index.d.ts +0 -0
  28. /package/src/lib/{ninetailedCorePlugin → NinetailedCorePlugin}/constants.d.ts +0 -0
@@ -1,53 +1,14 @@
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';
1
+ import { FEATURES, buildComponentViewEvent, logger, ConsoleLogSink, buildPageEvent, buildTrackEvent, buildIdentifyEvent, unionBy, pipe, PageviewProperties, Properties, Traits, isPageViewEvent, isTrackEvent, isIdentifyEvent, isComponentViewEvent, selectHasVariants, selectExperience, selectVariant as selectVariant$1, selectBaselineWithVariants, NinetailedApiClient, OnLogLogSink, OnErrorLogSink } 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
+ import { NinetailedAnalyticsPlugin, HAS_SEEN_COMPONENT, HAS_SEEN_ELEMENT } from '@ninetailed/experience.js-plugin-analytics';
3
4
  import Analytics from 'analytics';
4
5
  import { v4 } from 'uuid';
5
- import { z } from 'zod';
6
6
 
7
- const HAS_SEEN_COMPONENT = 'has_seen_component';
8
- const HAS_SEEN_ELEMENT = 'has_seen_element';
9
7
  const COMPONENT = 'component';
10
8
  const COMPONENT_START = 'componentStart';
11
9
  const PAGE_HIDDEN = 'page_hidden';
12
10
  const HAS_SEEN_STICKY_COMPONENT = 'sticky_component_view';
13
11
 
14
- /******************************************************************************
15
- Copyright (c) Microsoft Corporation.
16
-
17
- Permission to use, copy, modify, and/or distribute this software for any
18
- purpose with or without fee is hereby granted.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
21
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
22
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
23
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
24
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26
- PERFORMANCE OF THIS SOFTWARE.
27
- ***************************************************************************** */
28
-
29
- function __rest(s, e) {
30
- var t = {};
31
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
32
- t[p] = s[p];
33
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
34
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
35
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
36
- t[p[i]] = s[p[i]];
37
- }
38
- return t;
39
- }
40
-
41
- function __awaiter(thisArg, _arguments, P, generator) {
42
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
43
- return new (P || (P = Promise))(function (resolve, reject) {
44
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
45
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
46
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
47
- step((generator = generator.apply(thisArg, _arguments || [])).next());
48
- });
49
- }
50
-
51
12
  const buildClientLocale = () => navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;
52
13
 
53
14
  const buildClientNinetailedRequestContext = () => ({
@@ -60,15 +21,15 @@ const buildClientNinetailedRequestContext = () => ({
60
21
  }
61
22
  });
62
23
 
63
- /**
64
- * Similar to _.throttle but waits for the promise to resolve.
65
- * There is no "wait time" because you can simply await `Promise.timeout` inside `fn` to wait some time before the next call.
24
+ /**
25
+ * Similar to _.throttle but waits for the promise to resolve.
26
+ * There is no "wait time" because you can simply await `Promise.timeout` inside `fn` to wait some time before the next call.
66
27
  */
67
28
  function asyncThrottle(fn) {
68
29
  let runningPromise;
69
30
  let queuedPromise;
70
31
  let nextArgs;
71
- return args => __awaiter(this, void 0, void 0, function* () {
32
+ return async args => {
72
33
  if (runningPromise) {
73
34
  nextArgs = args;
74
35
  if (queuedPromise) {
@@ -85,7 +46,7 @@ function asyncThrottle(fn) {
85
46
  runningPromise = fn(args);
86
47
  return runningPromise;
87
48
  }
88
- });
49
+ };
89
50
  }
90
51
 
91
52
  const LEGACY_ANONYMOUS_ID = '__anon_id';
@@ -99,68 +60,262 @@ const CONSENT = '__nt-consent__';
99
60
  const SET_ENABLED_FEATURES = 'set-enabled-features';
100
61
  const EMPTY_MERGE_ID = 'nt:empty-merge-id';
101
62
 
102
- const PLUGIN_NAME = 'ninetailed';
63
+ const PLUGIN_NAME = 'ninetailed:core';
103
64
  const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
104
- const ninetailedCorePlugin = ({
105
- apiClient,
106
- locale,
107
- ninetailed,
108
- onInitProfileId,
109
- buildClientContext
110
- }) => {
111
- let _instance;
112
- let queue = [];
113
- let enabledFeatures = Object.values(FEATURES);
114
- const buildContext = buildClientContext || buildClientNinetailedRequestContext;
115
- const flush = () => __awaiter(void 0, void 0, void 0, function* () {
116
- const events = Object.assign([], queue);
65
+ class NinetailedCorePlugin extends NinetailedAnalyticsPlugin {
66
+ constructor({
67
+ apiClient,
68
+ locale,
69
+ ninetailed,
70
+ onInitProfileId,
71
+ buildClientContext
72
+ }) {
73
+ var _this;
74
+ super();
75
+ _this = this;
76
+ this.name = PLUGIN_NAME;
77
+ this._instance = void 0;
78
+ this.queue = [];
79
+ this.enabledFeatures = Object.values(FEATURES);
80
+ this.buildContext = buildClientNinetailedRequestContext;
81
+ this.onInitProfileId = void 0;
82
+ this.apiClient = void 0;
83
+ this.locale = void 0;
84
+ this.ninetailed = void 0;
85
+ this[HAS_SEEN_STICKY_COMPONENT] = async function ({
86
+ payload
87
+ }) {
88
+ const ctx = _this.buildContext();
89
+ return _this.enqueueEvent(buildComponentViewEvent({
90
+ messageId: payload.meta.rid,
91
+ timestamp: payload.meta.ts,
92
+ componentId: payload.componentId,
93
+ experienceId: payload.experienceId,
94
+ variantIndex: payload.variantIndex,
95
+ ctx
96
+ }));
97
+ };
98
+ this.methods = {
99
+ reset: async function (...args) {
100
+ logger.debug('Resetting profile.');
101
+ const instance = args[args.length - 1];
102
+ instance.dispatch({
103
+ type: PROFILE_RESET
104
+ });
105
+ instance.storage.removeItem(ANONYMOUS_ID);
106
+ instance.storage.removeItem(PROFILE_FALLBACK_CACHE);
107
+ instance.storage.removeItem(EXPERIENCES_FALLBACK_CACHE);
108
+ logger.debug('Removed old profile data from localstorage.');
109
+ if (typeof _this.onInitProfileId === 'function') {
110
+ const profileId = await _this.onInitProfileId(undefined);
111
+ if (typeof profileId === 'string') {
112
+ instance.storage.setItem(ANONYMOUS_ID, profileId);
113
+ }
114
+ }
115
+ await _this.ninetailed.track('nt_reset');
116
+ logger.info('Profile reset successful.');
117
+ await delay(10);
118
+ },
119
+ debug: async function (...args) {
120
+ const enabled = args[0];
121
+ const instance = args[args.length - 1];
122
+ const consoleLogSink = new ConsoleLogSink();
123
+ if (enabled) {
124
+ instance.storage.setItem(DEBUG_FLAG, true);
125
+ logger.addSink(consoleLogSink);
126
+ logger.info('Debug mode enabled.');
127
+ } else {
128
+ instance.storage.removeItem(DEBUG_FLAG);
129
+ logger.info('Debug mode disabled.');
130
+ logger.removeSink(consoleLogSink.name);
131
+ }
132
+ }
133
+ };
134
+ this.flush = asyncThrottle(this._flush.bind(this));
135
+ if (onInitProfileId) {
136
+ this.onInitProfileId = onInitProfileId;
137
+ }
138
+ if (buildClientContext) {
139
+ this.buildContext = buildClientContext;
140
+ }
141
+ this.apiClient = apiClient;
142
+ this.ninetailed = ninetailed;
143
+ this.locale = locale;
144
+ }
145
+ async initialize({
146
+ instance
147
+ }) {
148
+ this._instance = instance;
149
+ if (instance.storage.getItem(DEBUG_FLAG)) {
150
+ logger.addSink(new ConsoleLogSink());
151
+ logger.info('Ninetailed Debug Mode is enabled.');
152
+ }
153
+
154
+ // legacy support for the old anonymousId
155
+ const legacyAnonymousId = instance.storage.getItem(LEGACY_ANONYMOUS_ID);
156
+ if (legacyAnonymousId) {
157
+ logger.debug('Found legacy anonymousId, migrating to new one.', legacyAnonymousId);
158
+ instance.storage.setItem(ANONYMOUS_ID, legacyAnonymousId);
159
+ instance.storage.removeItem(LEGACY_ANONYMOUS_ID);
160
+ }
161
+ if (typeof this.onInitProfileId === 'function') {
162
+ const profileId = await this.onInitProfileId(instance.storage.getItem(ANONYMOUS_ID));
163
+ if (typeof profileId === 'string') {
164
+ instance.storage.setItem(ANONYMOUS_ID, profileId);
165
+ }
166
+ }
167
+ instance.on(SET_ENABLED_FEATURES, ({
168
+ payload
169
+ }) => {
170
+ this.enabledFeatures = payload.features || [];
171
+ });
172
+ logger.debug('Ninetailed Core plugin initialized.');
173
+ }
174
+ pageStart(params) {
175
+ return this.abortNonClientEvents(params);
176
+ }
177
+ async page({
178
+ payload
179
+ }) {
180
+ logger.info('Sending Page event.');
181
+ const ctx = this.buildContext();
182
+ return this.enqueueEvent(buildPageEvent({
183
+ messageId: payload.meta.rid,
184
+ timestamp: payload.meta.ts,
185
+ properties: payload.properties,
186
+ ctx
187
+ }));
188
+ }
189
+ trackStart(params) {
190
+ return this.abortNonClientEvents(params);
191
+ }
192
+ async track({
193
+ payload
194
+ }) {
195
+ logger.info('Sending Track event.');
196
+ const ctx = this.buildContext();
197
+ return this.enqueueEvent(buildTrackEvent({
198
+ messageId: payload.meta.rid,
199
+ timestamp: payload.meta.ts,
200
+ event: payload.event,
201
+ properties: payload.properties,
202
+ ctx
203
+ }));
204
+ }
205
+ identifyStart(params) {
206
+ return this.abortNonClientEvents(params);
207
+ }
208
+ async identify({
209
+ payload
210
+ }) {
211
+ logger.info('Sending Identify event.');
212
+ const ctx = this.buildContext();
213
+ if (payload.userId === EMPTY_MERGE_ID && (!payload.traits || typeof payload.traits === 'object' && Object.keys(payload.traits).length === 0)) {
214
+ logger.info('Skipping Identify event as no userId and no traits are set.');
215
+ return;
216
+ }
217
+ return this.enqueueEvent(buildIdentifyEvent({
218
+ messageId: payload.meta.rid,
219
+ timestamp: payload.meta.ts,
220
+ traits: payload.traits,
221
+ userId: payload.userId === EMPTY_MERGE_ID ? '' : payload.userId,
222
+ ctx
223
+ }));
224
+ }
225
+ getComponentViewTrackingThreshold() {
226
+ return 0;
227
+ }
228
+ async onTrackExperience(properties) {
229
+ if (properties.experience.sticky) {
230
+ await this.instance.dispatch({
231
+ type: HAS_SEEN_STICKY_COMPONENT,
232
+ componentId: properties.selectedVariant.id,
233
+ experienceId: properties.experience.id,
234
+ variantIndex: properties.selectedVariantIndex
235
+ });
236
+ this.flush();
237
+ }
238
+ return Promise.resolve();
239
+ }
240
+ onTrackComponent() {
241
+ return Promise.resolve();
242
+ }
243
+ setItemStart({
244
+ abort,
245
+ payload
246
+ }) {
247
+ if (![ANONYMOUS_ID, DEBUG_FLAG, PROFILE_FALLBACK_CACHE, EXPERIENCES_FALLBACK_CACHE, CONSENT].includes(payload.key)) {
248
+ return abort();
249
+ }
250
+ return payload;
251
+ }
252
+ async enqueueEvent(event) {
253
+ this.queue = unionBy([event], this.queue, 'messageId');
254
+ }
255
+ abortNonClientEvents({
256
+ abort,
257
+ payload
258
+ }) {
259
+ if (typeof window !== 'object') {
260
+ return abort();
261
+ }
262
+ return payload;
263
+ }
264
+ get instance() {
265
+ if (!this._instance) {
266
+ throw new Error('Ninetailed Core plugin not initialized.');
267
+ }
268
+ return this._instance;
269
+ }
270
+ async _flush() {
271
+ const events = Object.assign([], this.queue);
117
272
  logger.info('Start flushing events.');
118
- queue = [];
273
+ this.queue = [];
119
274
  if (!events.length) {
120
275
  return {
121
276
  success: true
122
277
  };
123
278
  }
124
279
  try {
125
- const anonymousId = _instance.storage.getItem(ANONYMOUS_ID);
280
+ const anonymousId = this.instance.storage.getItem(ANONYMOUS_ID);
126
281
  const {
127
282
  profile,
128
283
  experiences
129
- } = yield apiClient.upsertProfile({
284
+ } = await this.apiClient.upsertProfile({
130
285
  profileId: anonymousId,
131
286
  events
132
287
  }, {
133
- locale,
134
- enabledFeatures
288
+ locale: this.locale,
289
+ enabledFeatures: this.enabledFeatures
135
290
  });
136
- _instance.storage.setItem(ANONYMOUS_ID, profile.id);
137
- _instance.storage.setItem(PROFILE_FALLBACK_CACHE, profile);
138
- _instance.storage.setItem(EXPERIENCES_FALLBACK_CACHE, experiences);
291
+ this.instance.storage.setItem(ANONYMOUS_ID, profile.id);
292
+ this.instance.storage.setItem(PROFILE_FALLBACK_CACHE, profile);
293
+ this.instance.storage.setItem(EXPERIENCES_FALLBACK_CACHE, experiences);
139
294
  logger.debug('Profile from api: ', profile);
140
295
  logger.debug('Experiences from api: ', experiences);
141
- _instance.dispatch({
296
+ this.instance.dispatch({
142
297
  type: PROFILE_CHANGE,
143
298
  profile,
144
299
  experiences
145
300
  });
146
- yield delay(20);
301
+ await delay(20);
147
302
  return {
148
303
  success: true
149
304
  };
150
305
  } catch (error) {
151
306
  logger.debug('An error occurred during flushing the events: ', error);
152
- const fallbackProfile = _instance.storage.getItem(PROFILE_FALLBACK_CACHE);
153
- const fallbackExperiences = _instance.storage.getItem(EXPERIENCES_FALLBACK_CACHE) || [];
307
+ const fallbackProfile = this.instance.storage.getItem(PROFILE_FALLBACK_CACHE);
308
+ const fallbackExperiences = this.instance.storage.getItem(EXPERIENCES_FALLBACK_CACHE) || [];
154
309
  if (fallbackProfile) {
155
310
  logger.debug('Found a fallback profile - will use this.');
156
- _instance.dispatch({
311
+ this.instance.dispatch({
157
312
  type: PROFILE_CHANGE,
158
313
  profile: fallbackProfile,
159
314
  experiences: fallbackExperiences
160
315
  });
161
316
  } else {
162
317
  logger.debug('No fallback profile found - setting profile to null.');
163
- _instance.dispatch({
318
+ this.instance.dispatch({
164
319
  type: PROFILE_CHANGE,
165
320
  profile: null,
166
321
  experiences: fallbackExperiences,
@@ -171,166 +326,27 @@ const ninetailedCorePlugin = ({
171
326
  success: false
172
327
  };
173
328
  }
174
- });
175
- const enqueueEvent = event => __awaiter(void 0, void 0, void 0, function* () {
176
- queue = unionBy([event], queue, 'messageId');
177
- });
178
- const abortNonClientEvents = ({
179
- abort,
180
- payload
181
- }) => {
182
- if (typeof window !== 'object') {
183
- return abort();
184
- }
185
- return payload;
186
- };
187
- return {
188
- name: 'ninetailed',
189
- config: {},
190
- initialize: ({
191
- instance
192
- }) => __awaiter(void 0, void 0, void 0, function* () {
193
- _instance = instance;
194
- if (instance.storage.getItem(DEBUG_FLAG)) {
195
- logger.addSink(new ConsoleLogSink());
196
- logger.info('Ninetailed Debug Mode is enabled.');
197
- }
198
- // legacy support for the old anonymousId
199
- const legacyAnonymousId = instance.storage.getItem(LEGACY_ANONYMOUS_ID);
200
- if (legacyAnonymousId) {
201
- logger.debug('Found legacy anonymousId, migrating to new one.', legacyAnonymousId);
202
- instance.storage.setItem(ANONYMOUS_ID, legacyAnonymousId);
203
- instance.storage.removeItem(LEGACY_ANONYMOUS_ID);
204
- }
205
- if (typeof onInitProfileId === 'function') {
206
- const profileId = yield onInitProfileId(instance.storage.getItem(ANONYMOUS_ID));
207
- if (typeof profileId === 'string') {
208
- instance.storage.setItem(ANONYMOUS_ID, profileId);
209
- }
210
- }
211
- instance.on(SET_ENABLED_FEATURES, ({
212
- payload
213
- }) => {
214
- enabledFeatures = payload.features || [];
215
- });
216
- logger.debug('Ninetailed Core plugin initialized.');
217
- }),
218
- flush: asyncThrottle(flush),
219
- pageStart: params => {
220
- return abortNonClientEvents(params);
221
- },
222
- page: ({
223
- payload
224
- }) => __awaiter(void 0, void 0, void 0, function* () {
225
- logger.info('Sending Page event.');
226
- const ctx = buildContext();
227
- return enqueueEvent(buildPageEvent({
228
- messageId: payload.meta.rid,
229
- timestamp: payload.meta.ts,
230
- properties: payload.properties,
231
- ctx
232
- }));
233
- }),
234
- trackStart: params => {
235
- return abortNonClientEvents(params);
236
- },
237
- track: ({
238
- payload
239
- }) => __awaiter(void 0, void 0, void 0, function* () {
240
- logger.info('Sending Track event.');
241
- const ctx = buildContext();
242
- return enqueueEvent(buildTrackEvent({
243
- messageId: payload.meta.rid,
244
- timestamp: payload.meta.ts,
245
- event: payload.event,
246
- properties: payload.properties,
247
- ctx
248
- }));
249
- }),
250
- identifyStart: params => {
251
- return abortNonClientEvents(params);
252
- },
253
- identify: ({
254
- payload
255
- }) => __awaiter(void 0, void 0, void 0, function* () {
256
- logger.info('Sending Identify event.');
257
- const ctx = buildContext();
258
- if (payload.userId === EMPTY_MERGE_ID && (!payload.traits || typeof payload.traits === 'object' && Object.keys(payload.traits).length === 0)) {
259
- logger.info('Skipping Identify event as no userId and no traits are set.');
260
- return;
261
- }
262
- return enqueueEvent(buildIdentifyEvent({
263
- messageId: payload.meta.rid,
264
- timestamp: payload.meta.ts,
265
- traits: payload.traits,
266
- userId: payload.userId === EMPTY_MERGE_ID ? '' : payload.userId,
267
- ctx
268
- }));
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
- }),
284
- setItemStart: ({
285
- abort,
286
- payload
287
- }) => {
288
- if (![ANONYMOUS_ID, DEBUG_FLAG, PROFILE_FALLBACK_CACHE, EXPERIENCES_FALLBACK_CACHE, CONSENT].includes(payload.key)) {
289
- return abort();
290
- }
291
- return payload;
292
- },
293
- methods: {
294
- reset: (...args) => __awaiter(void 0, void 0, void 0, function* () {
295
- logger.debug('Resetting profile.');
296
- const instance = args[args.length - 1];
297
- instance.dispatch({
298
- type: PROFILE_RESET
299
- });
300
- instance.storage.removeItem(ANONYMOUS_ID);
301
- instance.storage.removeItem(PROFILE_FALLBACK_CACHE);
302
- instance.storage.removeItem(EXPERIENCES_FALLBACK_CACHE);
303
- logger.debug('Removed old profile data from localstorage.');
304
- if (typeof onInitProfileId === 'function') {
305
- const profileId = yield onInitProfileId(undefined);
306
- if (typeof profileId === 'string') {
307
- instance.storage.setItem(ANONYMOUS_ID, profileId);
308
- }
309
- }
310
- yield ninetailed.track('nt_reset');
311
- logger.info('Profile reset successful.');
312
- yield delay(10);
313
- }),
314
- debug: (...args) => __awaiter(void 0, void 0, void 0, function* () {
315
- const enabled = args[0];
316
- const instance = args[args.length - 1];
317
- const consoleLogSink = new ConsoleLogSink();
318
- if (enabled) {
319
- instance.storage.setItem(DEBUG_FLAG, true);
320
- logger.addSink(consoleLogSink);
321
- logger.info('Debug mode enabled.');
322
- } else {
323
- instance.storage.removeItem(DEBUG_FLAG);
324
- logger.info('Debug mode disabled.');
325
- logger.removeSink(consoleLogSink.name);
326
- }
327
- })
328
- }
329
- };
330
- };
329
+ }
330
+ }
331
+
332
+ function _objectWithoutPropertiesLoose(source, excluded) {
333
+ if (source == null) return {};
334
+ var target = {};
335
+ var sourceKeys = Object.keys(source);
336
+ var key, i;
337
+ for (i = 0; i < sourceKeys.length; i++) {
338
+ key = sourceKeys[i];
339
+ if (excluded.indexOf(key) >= 0) continue;
340
+ target[key] = source[key];
341
+ }
342
+ return target;
343
+ }
331
344
 
332
345
  class ElementSeenObserver {
333
346
  constructor(_options) {
347
+ this._intersectionObserver = void 0;
348
+ this._elementDelays = void 0;
349
+ this._intersectionTimers = void 0;
334
350
  this._options = _options;
335
351
  this._elementDelays = new WeakMap();
336
352
  this._intersectionTimers = new WeakMap();
@@ -345,27 +361,33 @@ class ElementSeenObserver {
345
361
  target
346
362
  } = entry;
347
363
  if (isIntersecting) {
348
- const delay = this._elementDelays.get(target);
349
- const timeOut = window.setTimeout(() => {
350
- this._options.onElementSeen(target);
351
- }, delay);
352
- this._intersectionTimers.set(target, timeOut);
364
+ const delays = this._elementDelays.get(target);
365
+ delays == null || delays.forEach(delay => {
366
+ const timeOut = window.setTimeout(() => {
367
+ this._options.onElementSeen(target, delay);
368
+ }, delay);
369
+ const currentTimers = this._intersectionTimers.get(target) || [];
370
+ this._intersectionTimers.set(target, [...currentTimers, timeOut]);
371
+ });
353
372
  } else {
354
- const timeOut = this._intersectionTimers.get(target);
355
- if (typeof timeOut !== 'undefined') {
356
- window.clearTimeout(timeOut);
357
- }
373
+ const timeOuts = this._intersectionTimers.get(target);
374
+ timeOuts == null || timeOuts.forEach(timeOut => {
375
+ if (typeof timeOut !== 'undefined') {
376
+ window.clearTimeout(timeOut);
377
+ }
378
+ });
358
379
  }
359
380
  });
360
381
  }
361
382
  observe(element, options) {
362
- var _a, _b;
363
- this._elementDelays.set(element, (_a = options === null || options === void 0 ? void 0 : options.delay) !== null && _a !== void 0 ? _a : 2000);
364
- (_b = this._intersectionObserver) === null || _b === void 0 ? void 0 : _b.observe(element);
383
+ var _this$_intersectionOb;
384
+ const delays = this._elementDelays.get(element) || [];
385
+ this._elementDelays.set(element, Array.from(new Set([...delays, (options == null ? void 0 : options.delay) || 0])));
386
+ (_this$_intersectionOb = this._intersectionObserver) == null || _this$_intersectionOb.observe(element);
365
387
  }
366
388
  unobserve(element) {
367
- var _a;
368
- (_a = this._intersectionObserver) === null || _a === void 0 ? void 0 : _a.unobserve(element);
389
+ var _this$_intersectionOb2;
390
+ (_this$_intersectionOb2 = this._intersectionObserver) == null || _this$_intersectionOb2.unobserve(element);
369
391
  }
370
392
  }
371
393
 
@@ -388,7 +410,7 @@ const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
388
410
  experienceId,
389
411
  variantIndex
390
412
  };
391
- }).filter(x => !!x).reduce((acc, curr) => Object.assign(Object.assign({}, acc), {
413
+ }).filter(x => !!x).reduce((acc, curr) => Object.assign({}, acc, {
392
414
  [curr.experienceId]: curr.variantIndex
393
415
  }), {});
394
416
  };
@@ -493,42 +515,43 @@ const makeExperienceSelectMiddleware = ({
493
515
 
494
516
  class EventBuilder {
495
517
  constructor(buildRequestContext) {
518
+ this.buildRequestContext = void 0;
496
519
  this.buildRequestContext = buildRequestContext || buildClientNinetailedRequestContext;
497
520
  }
498
521
  page(properties, data) {
499
- return buildPageEvent(Object.assign(Object.assign({
500
- messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4()
501
- }, data), {
522
+ return buildPageEvent(Object.assign({
523
+ messageId: (data == null ? void 0 : data.messageId) || v4()
524
+ }, data, {
502
525
  timestamp: Date.now(),
503
526
  properties: properties || {},
504
527
  ctx: this.buildRequestContext()
505
528
  }));
506
529
  }
507
530
  track(event, properties, data) {
508
- return buildTrackEvent(Object.assign(Object.assign({
509
- messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4(),
531
+ return buildTrackEvent(Object.assign({
532
+ messageId: (data == null ? void 0 : data.messageId) || v4(),
510
533
  timestamp: Date.now()
511
- }, data), {
534
+ }, data, {
512
535
  event,
513
536
  properties: properties || {},
514
537
  ctx: this.buildRequestContext()
515
538
  }));
516
539
  }
517
540
  identify(userId, traits, data) {
518
- return buildIdentifyEvent(Object.assign(Object.assign({
519
- messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4(),
541
+ return buildIdentifyEvent(Object.assign({
542
+ messageId: (data == null ? void 0 : data.messageId) || v4(),
520
543
  timestamp: Date.now()
521
- }, data), {
544
+ }, data, {
522
545
  traits: traits || {},
523
546
  userId: userId || '',
524
547
  ctx: this.buildRequestContext()
525
548
  }));
526
549
  }
527
550
  component(componentId, experienceId, variantIndex, data) {
528
- return buildComponentViewEvent(Object.assign(Object.assign({
529
- messageId: (data === null || data === void 0 ? void 0 : data.messageId) || v4(),
551
+ return buildComponentViewEvent(Object.assign({
552
+ messageId: (data == null ? void 0 : data.messageId) || v4(),
530
553
  timestamp: Date.now()
531
- }, data), {
554
+ }, data, {
532
555
  componentId,
533
556
  experienceId: experienceId || '',
534
557
  variantIndex: variantIndex || 0,
@@ -537,13 +560,19 @@ class EventBuilder {
537
560
  }
538
561
  }
539
562
 
540
- const buildOverrideMiddleware = experienceSelectionMiddleware => _a => {
541
- var {
563
+ const hasComponentViewTrackingThreshold = arg => {
564
+ return typeof arg === 'object' && arg !== null && 'getComponentViewTrackingThreshold' in arg && typeof arg['getComponentViewTrackingThreshold'] === 'function';
565
+ };
566
+
567
+ const _excluded = ["experience", "variant", "variantIndex"],
568
+ _excluded2 = ["element"];
569
+ const buildOverrideMiddleware = experienceSelectionMiddleware => _ref => {
570
+ let {
542
571
  experience: originalExperience,
543
572
  variant: originalVariant,
544
573
  variantIndex: originalVariantIndex
545
- } = _a,
546
- other = __rest(_a, ["experience", "variant", "variantIndex"]);
574
+ } = _ref,
575
+ other = _objectWithoutPropertiesLoose(_ref, _excluded);
547
576
  const {
548
577
  experience,
549
578
  variant,
@@ -553,8 +582,8 @@ const buildOverrideMiddleware = experienceSelectionMiddleware => _a => {
553
582
  variant: originalVariant,
554
583
  variantIndex: originalVariantIndex
555
584
  });
556
- return Object.assign(Object.assign({}, other), {
557
- audience: (experience === null || experience === void 0 ? void 0 : experience.audience) ? experience.audience : null,
585
+ return Object.assign({}, other, {
586
+ audience: experience != null && experience.audience ? experience.audience : null,
558
587
  experience,
559
588
  variant,
560
589
  variantIndex
@@ -574,16 +603,30 @@ class Ninetailed {
574
603
  storageImpl,
575
604
  useClientSideEvaluation = false
576
605
  } = {}) {
606
+ var _this = this;
607
+ this.instance = void 0;
608
+ this._profileState = void 0;
577
609
  this.isInitialized = false;
578
- this.page = (data, options) => __awaiter(this, void 0, void 0, function* () {
610
+ this.apiClient = void 0;
611
+ this.ninetailedCorePlugin = void 0;
612
+ this.elementSeenObserver = void 0;
613
+ this.observedElements = void 0;
614
+ this.clientId = void 0;
615
+ this.environment = void 0;
616
+ this.plugins = void 0;
617
+ this.logger = void 0;
618
+ this.componentViewTrackingThreshold = void 0;
619
+ this.useClientSideEvaluation = void 0;
620
+ this.eventBuilder = void 0;
621
+ this.page = async function (data, options) {
579
622
  try {
580
623
  const result = PageviewProperties.partial().default({}).safeParse(data);
581
624
  if (!result.success) {
582
625
  throw new Error(`[Validation Error] "page" was called with invalid params. Page data is not valid: ${result.error.format()}`);
583
626
  }
584
- yield this.waitUntilInitialized();
585
- yield this.instance.page(data, this.buildOptions(options));
586
- return this.ninetailedCorePlugin.flush();
627
+ await _this.waitUntilInitialized();
628
+ await _this.instance.page(data, _this.buildOptions(options));
629
+ return _this.ninetailedCorePlugin.flush();
587
630
  } catch (error) {
588
631
  logger.error(error);
589
632
  if (error instanceof RangeError) {
@@ -591,16 +634,16 @@ class Ninetailed {
591
634
  }
592
635
  throw error;
593
636
  }
594
- });
595
- this.track = (event, properties, options) => __awaiter(this, void 0, void 0, function* () {
637
+ };
638
+ this.track = async function (event, properties, options) {
596
639
  try {
597
640
  const result = Properties.default({}).safeParse(properties);
598
641
  if (!result.success) {
599
642
  throw new Error(`[Validation Error] "track" was called with invalid params. Properties are no valid json object: ${result.error.format()}`);
600
643
  }
601
- yield this.waitUntilInitialized();
602
- yield this.instance.track(event.toString(), result.data, this.buildOptions(options));
603
- return this.ninetailedCorePlugin.flush();
644
+ await _this.waitUntilInitialized();
645
+ await _this.instance.track(event.toString(), result.data, _this.buildOptions(options));
646
+ return _this.ninetailedCorePlugin.flush();
604
647
  } catch (error) {
605
648
  logger.error(error);
606
649
  if (error instanceof RangeError) {
@@ -608,16 +651,16 @@ class Ninetailed {
608
651
  }
609
652
  throw error;
610
653
  }
611
- });
612
- this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
654
+ };
655
+ this.identify = async function (uid, traits, options) {
613
656
  try {
614
657
  const result = Traits.default({}).safeParse(traits);
615
658
  if (!result.success) {
616
659
  throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
617
660
  }
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();
661
+ await _this.waitUntilInitialized();
662
+ await _this.instance.identify(uid && uid.toString() !== '' ? uid.toString() : EMPTY_MERGE_ID, result.data, _this.buildOptions(options));
663
+ return _this.ninetailedCorePlugin.flush();
621
664
  } catch (error) {
622
665
  logger.error(error);
623
666
  if (error instanceof RangeError) {
@@ -625,22 +668,22 @@ class Ninetailed {
625
668
  }
626
669
  throw error;
627
670
  }
628
- });
629
- this.batch = events => __awaiter(this, void 0, void 0, function* () {
671
+ };
672
+ this.batch = async function (events) {
630
673
  try {
631
- yield this.waitUntilInitialized();
674
+ await _this.waitUntilInitialized();
632
675
  const promises = events.map(event => {
633
676
  if (isPageViewEvent(event)) {
634
- return this.instance.page(event.properties);
677
+ return _this.instance.page(event.properties);
635
678
  }
636
679
  if (isTrackEvent(event)) {
637
- return this.instance.track(event.event, event.properties);
680
+ return _this.instance.track(event.event, event.properties);
638
681
  }
639
682
  if (isIdentifyEvent(event)) {
640
- return this.instance.identify(event.userId || EMPTY_MERGE_ID, event.traits);
683
+ return _this.instance.identify(event.userId || EMPTY_MERGE_ID, event.traits);
641
684
  }
642
685
  if (isComponentViewEvent(event)) {
643
- return this.instance.dispatch({
686
+ return _this.instance.dispatch({
644
687
  experienceId: event.experienceId,
645
688
  componentId: event.componentId,
646
689
  variantIndex: event.variantIndex,
@@ -649,8 +692,8 @@ class Ninetailed {
649
692
  }
650
693
  return Promise.resolve();
651
694
  });
652
- yield Promise.all(promises);
653
- return this.ninetailedCorePlugin.flush();
695
+ await Promise.all(promises);
696
+ return _this.ninetailedCorePlugin.flush();
654
697
  } catch (error) {
655
698
  logger.error(error);
656
699
  if (error instanceof RangeError) {
@@ -658,21 +701,21 @@ class Ninetailed {
658
701
  }
659
702
  throw error;
660
703
  }
661
- });
662
- this.trackStickyComponentView = ({
704
+ };
705
+ this.trackStickyComponentView = async function ({
663
706
  experienceId,
664
707
  componentId,
665
708
  variantIndex
666
- }) => __awaiter(this, void 0, void 0, function* () {
709
+ }) {
667
710
  try {
668
- yield this.waitUntilInitialized();
669
- yield this.instance.dispatch({
711
+ await _this.waitUntilInitialized();
712
+ await _this.instance.dispatch({
670
713
  experienceId,
671
714
  componentId,
672
715
  variantIndex,
673
716
  type: HAS_SEEN_STICKY_COMPONENT
674
717
  });
675
- return this.ninetailedCorePlugin.flush();
718
+ return _this.ninetailedCorePlugin.flush();
676
719
  } catch (error) {
677
720
  logger.error(error);
678
721
  if (error instanceof RangeError) {
@@ -680,18 +723,18 @@ class Ninetailed {
680
723
  }
681
724
  throw error;
682
725
  }
683
- });
684
- /**
685
- * @deprecated The legacy datamodel is not recommended anymore
686
- * Will be removed in the next version of the SDK
726
+ };
727
+ /**
728
+ * @deprecated The legacy datamodel is not recommended anymore
729
+ * Will be removed in the next version of the SDK
687
730
  */
688
- this.trackHasSeenComponent = properties => __awaiter(this, void 0, void 0, function* () {
689
- return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
731
+ this.trackHasSeenComponent = async function (properties) {
732
+ return _this.instance.dispatch(Object.assign({}, properties, {
690
733
  type: HAS_SEEN_COMPONENT
691
734
  }));
692
- });
735
+ };
693
736
  this.trackComponentView = properties => {
694
- return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
737
+ return this.instance.dispatch(Object.assign({}, properties, {
695
738
  type: HAS_SEEN_ELEMENT
696
739
  }));
697
740
  };
@@ -699,7 +742,7 @@ class Ninetailed {
699
742
  const {
700
743
  element
701
744
  } = payload,
702
- remaingPayload = __rest(payload, ["element"]);
745
+ remaingPayload = _objectWithoutPropertiesLoose(payload, _excluded2);
703
746
  if (!(element instanceof Element)) {
704
747
  const isObject = typeof element === 'object' && element !== null;
705
748
  const constructorName = isObject ? element.constructor.name : '';
@@ -707,49 +750,64 @@ class Ninetailed {
707
750
  logger.warn(`ElementSeenObserver.observeElement was called with an invalid element. Expected an Element but got ${typeof element}${isConstructorNameNotObject ? ` of type ${constructorName}` : ''}. This call will be ignored.`);
708
751
  } else {
709
752
  this.observedElements.set(element, remaingPayload);
710
- this.elementSeenObserver.observe(element, Object.assign({
711
- delay: this.componentViewTrackingThreshold
712
- }, options));
753
+ const delays = this.pluginsWithCustomComponentViewThreshold.map(plugin => plugin.getComponentViewTrackingThreshold());
754
+ const uniqueDelays = Array.from(new Set([...delays, (options == null ? void 0 : options.delay) || this.componentViewTrackingThreshold]));
755
+ uniqueDelays.forEach(delay => {
756
+ this.elementSeenObserver.observe(element, {
757
+ delay
758
+ });
759
+ });
713
760
  }
714
761
  };
715
762
  this.unobserveElement = element => {
716
763
  this.observedElements.delete(element);
717
764
  this.elementSeenObserver.unobserve(element);
718
765
  };
719
- this.onElementSeen = element => {
766
+ this.onElementSeen = (element, delay) => {
720
767
  const payload = this.observedElements.get(element);
721
768
  if (typeof payload !== 'undefined') {
722
- this.trackComponentView(Object.assign({
723
- element
724
- }, payload));
769
+ const pluginNamesInterestedInSeenElementMessage = [...this.pluginsWithCustomComponentViewThreshold.filter(plugin => plugin.getComponentViewTrackingThreshold() === delay), ...this.plugins.filter(plugin => !hasComponentViewTrackingThreshold(plugin))].map(plugin => plugin.name);
770
+ if (pluginNamesInterestedInSeenElementMessage.length === 0) {
771
+ return;
772
+ }
773
+ this.instance.dispatch(Object.assign({}, payload, {
774
+ element,
775
+ type: HAS_SEEN_ELEMENT,
776
+ plugins: Object.assign({
777
+ all: false
778
+ }, pluginNamesInterestedInSeenElementMessage.reduce((acc, curr) => Object.assign({}, acc, {
779
+ [curr]: true
780
+ }), {}))
781
+ }));
725
782
  }
726
783
  };
727
- this.reset = () => __awaiter(this, void 0, void 0, function* () {
728
- yield this.waitUntilInitialized();
784
+ this.reset = async function () {
785
+ await _this.waitUntilInitialized();
786
+
729
787
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
730
788
  // @ts-ignore
731
- this.instance.plugins[PLUGIN_NAME].reset();
732
- });
733
- this.debug = enabled => __awaiter(this, void 0, void 0, function* () {
734
- yield this.waitUntilInitialized();
789
+ _this.instance.plugins[PLUGIN_NAME].reset();
790
+ };
791
+ this.debug = async function (enabled) {
792
+ await _this.waitUntilInitialized();
735
793
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
736
794
  // @ts-ignore
737
- this.instance.plugins[PLUGIN_NAME].debug(enabled);
738
- });
795
+ _this.instance.plugins[PLUGIN_NAME].debug(enabled);
796
+ };
739
797
  this.onProfileChange = cb => {
740
798
  cb(this.profileState);
741
799
  return this.instance.on(PROFILE_CHANGE, ({
742
800
  payload
743
801
  }) => {
744
802
  if (payload.error) {
745
- cb(Object.assign(Object.assign({}, this._profileState), {
803
+ cb(Object.assign({}, this._profileState, {
746
804
  status: 'error',
747
805
  profile: payload.profile,
748
806
  experiences: payload.experiences,
749
807
  error: payload.error
750
808
  }));
751
809
  } else {
752
- cb(Object.assign(Object.assign({}, this._profileState), {
810
+ cb(Object.assign({}, this._profileState, {
753
811
  status: 'success',
754
812
  profile: payload.profile,
755
813
  experiences: payload.experiences,
@@ -793,11 +851,11 @@ class Ninetailed {
793
851
  middlewareChangeListeners.push(removeListeners);
794
852
  const overrideResult = buildOverrideMiddleware(experienceSelectionMiddleware);
795
853
  const hasVariants = experiences.map(experience => selectHasVariants(experience, baseline)).reduce((acc, curr) => acc || curr, false);
796
- const baseReturn = Object.assign(Object.assign({}, profileState), {
854
+ const baseReturn = Object.assign({}, profileState, {
797
855
  hasVariants,
798
856
  baseline
799
857
  });
800
- const emptyReturn = Object.assign(Object.assign({}, baseReturn), {
858
+ const emptyReturn = Object.assign({}, baseReturn, {
801
859
  experience: null,
802
860
  variant: baseline,
803
861
  variantIndex: 0,
@@ -807,14 +865,14 @@ class Ninetailed {
807
865
  error: null
808
866
  });
809
867
  if (profileState.status === 'loading') {
810
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
868
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
811
869
  loading: true,
812
870
  status: 'loading'
813
871
  })));
814
872
  return;
815
873
  }
816
874
  if (profileState.status === 'error') {
817
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
875
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
818
876
  loading: false,
819
877
  status: 'error',
820
878
  error: profileState.error
@@ -826,7 +884,7 @@ class Ninetailed {
826
884
  experiences: selectedExperiences
827
885
  } = profileState;
828
886
  if (!profile || !selectedExperiences) {
829
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
887
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
830
888
  loading: false,
831
889
  status: 'error',
832
890
  error: new Error('No Profile or Selected Experiences were returned by the API')
@@ -839,7 +897,7 @@ class Ninetailed {
839
897
  profile
840
898
  });
841
899
  if (!_experience) {
842
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
900
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
843
901
  loading: false,
844
902
  status: 'success',
845
903
  profile
@@ -854,7 +912,7 @@ class Ninetailed {
854
912
  experience: _experience,
855
913
  profile
856
914
  });
857
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, baseReturn), {
915
+ setSelectedVariant(overrideResult(Object.assign({}, baseReturn, {
858
916
  status: 'success',
859
917
  loading: false,
860
918
  error: null,
@@ -870,9 +928,9 @@ class Ninetailed {
870
928
  const experience = experiences.find(experience => selectedExperiences.some(selectedExperience => selectedExperience.experienceId === experience.id));
871
929
  const selectedExperience = selectedExperiences.find(({
872
930
  experienceId
873
- }) => experienceId === (experience === null || experience === void 0 ? void 0 : experience.id));
931
+ }) => experienceId === (experience == null ? void 0 : experience.id));
874
932
  if (!experience || !selectedExperience) {
875
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
933
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
876
934
  loading: false,
877
935
  status: 'success',
878
936
  profile
@@ -881,7 +939,7 @@ class Ninetailed {
881
939
  }
882
940
  const baselineVariants = selectBaselineWithVariants(experience, baseline);
883
941
  if (!baselineVariants) {
884
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
942
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
885
943
  loading: false,
886
944
  status: 'success',
887
945
  profile
@@ -891,16 +949,16 @@ class Ninetailed {
891
949
  const {
892
950
  variants
893
951
  } = baselineVariants;
894
- const variant = variants[selectedExperience.variantIndex - 1];
952
+ const variant = [baseline, ...variants][selectedExperience.variantIndex];
895
953
  if (!variant) {
896
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
954
+ setSelectedVariant(overrideResult(Object.assign({}, emptyReturn, {
897
955
  loading: false,
898
956
  status: 'success',
899
957
  profile
900
958
  })));
901
959
  return;
902
960
  }
903
- setSelectedVariant(overrideResult(Object.assign(Object.assign({}, baseReturn), {
961
+ setSelectedVariant(overrideResult(Object.assign({}, baseReturn, {
904
962
  status: 'success',
905
963
  loading: false,
906
964
  error: null,
@@ -965,7 +1023,7 @@ class Ninetailed {
965
1023
  preview
966
1024
  });
967
1025
  }
968
- this.plugins = (plugins !== null && plugins !== void 0 ? plugins : []).flat();
1026
+ this.plugins = (plugins != null ? plugins : []).flat();
969
1027
  this.plugins.forEach(plugin => {
970
1028
  if (acceptsCredentials(plugin) && this.clientId && this.environment) {
971
1029
  plugin.setCredentials({
@@ -989,7 +1047,7 @@ class Ninetailed {
989
1047
  }
990
1048
  this.eventBuilder = new EventBuilder(buildClientContext);
991
1049
  this.logger = logger;
992
- this.ninetailedCorePlugin = ninetailedCorePlugin({
1050
+ this.ninetailedCorePlugin = new NinetailedCorePlugin({
993
1051
  apiClient: this.apiClient,
994
1052
  locale,
995
1053
  requestTimeout,
@@ -1003,11 +1061,12 @@ class Ninetailed {
1003
1061
  }, storageImpl ? {
1004
1062
  storage: storageImpl
1005
1063
  } : {}));
1006
- const detachOnReadyListener = this.instance.on('ready', () => {
1064
+ const _detachOnReadyListener = this.instance.on('ready', () => {
1007
1065
  this.isInitialized = true;
1008
1066
  logger.info('Ninetailed Experience.js SDK is completely initialized.');
1009
- detachOnReadyListener();
1067
+ _detachOnReadyListener();
1010
1068
  });
1069
+
1011
1070
  // put in private method
1012
1071
  this.onProfileChange(profileState => {
1013
1072
  this._profileState = profileState;
@@ -1029,6 +1088,9 @@ class Ninetailed {
1029
1088
  }
1030
1089
  this.registerWindowHandlers();
1031
1090
  }
1091
+ get pluginsWithCustomComponentViewThreshold() {
1092
+ return [this.ninetailedCorePlugin, ...this.plugins].filter(plugin => hasComponentViewTrackingThreshold(plugin));
1093
+ }
1032
1094
  get profileState() {
1033
1095
  return this._profileState;
1034
1096
  }
@@ -1059,7 +1121,7 @@ const selectVariant = (baseline, variants, {
1059
1121
  if (status === 'loading') {
1060
1122
  return {
1061
1123
  loading: true,
1062
- variant: Object.assign(Object.assign({}, baseline), {
1124
+ variant: Object.assign({}, baseline, {
1063
1125
  id: 'baseline',
1064
1126
  audience: {
1065
1127
  id: 'baseline'
@@ -1075,7 +1137,7 @@ const selectVariant = (baseline, variants, {
1075
1137
  if (status === 'error') {
1076
1138
  return {
1077
1139
  loading: false,
1078
- variant: Object.assign(Object.assign({}, baseline), {
1140
+ variant: Object.assign({}, baseline, {
1079
1141
  id: 'baseline',
1080
1142
  audience: {
1081
1143
  id: 'baseline'
@@ -1089,19 +1151,19 @@ const selectVariant = (baseline, variants, {
1089
1151
  };
1090
1152
  }
1091
1153
  const variant = variants.find(variant => {
1092
- var _a, _b;
1093
- return (_a = profile === null || profile === void 0 ? void 0 : profile.audiences) === null || _a === void 0 ? void 0 : _a.includes((_b = variant.audience) === null || _b === void 0 ? void 0 : _b.id);
1154
+ var _profile$audiences, _variant$audience;
1155
+ return profile == null || (_profile$audiences = profile.audiences) == null ? void 0 : _profile$audiences.includes((_variant$audience = variant.audience) == null ? void 0 : _variant$audience.id);
1094
1156
  });
1095
1157
  if (variant) {
1096
- if ((options === null || options === void 0 ? void 0 : options.holdout) || -1 > ((profile === null || profile === void 0 ? void 0 : profile.random) || 0)) {
1158
+ if (options != null && options.holdout || -1 > ((profile == null ? void 0 : profile.random) || 0)) {
1097
1159
  return {
1098
1160
  loading: false,
1099
- variant: Object.assign(Object.assign({}, baseline), {
1161
+ variant: Object.assign({}, baseline, {
1100
1162
  audience: {
1101
1163
  id: 'baseline'
1102
1164
  }
1103
1165
  }),
1104
- audience: Object.assign(Object.assign({}, variant.audience), {
1166
+ audience: Object.assign({}, variant.audience, {
1105
1167
  id: variant.audience.id
1106
1168
  }),
1107
1169
  isPersonalized: false,
@@ -1111,19 +1173,20 @@ const selectVariant = (baseline, variants, {
1111
1173
  return {
1112
1174
  loading: false,
1113
1175
  variant,
1114
- audience: Object.assign(Object.assign({}, variant.audience), {
1176
+ audience: Object.assign({}, variant.audience, {
1115
1177
  id: variant.audience.id
1116
1178
  }),
1117
1179
  isPersonalized: true,
1118
1180
  error: null
1119
1181
  };
1120
1182
  }
1121
- /**
1122
- * There was no matching audience found.
1183
+
1184
+ /**
1185
+ * There was no matching audience found.
1123
1186
  */
1124
1187
  return {
1125
1188
  loading: false,
1126
- variant: Object.assign(Object.assign({}, baseline), {
1189
+ variant: Object.assign({}, baseline, {
1127
1190
  id: 'baseline',
1128
1191
  audience: {
1129
1192
  id: 'baseline'
@@ -1137,39 +1200,4 @@ const selectVariant = (baseline, variants, {
1137
1200
  };
1138
1201
  };
1139
1202
 
1140
- const TrackComponentProperties = z.object({
1141
- variant: z.object({
1142
- id: z.string()
1143
- }),
1144
- audience: z.object({
1145
- id: z.string()
1146
- }),
1147
- isPersonalized: z.boolean()
1148
- });
1149
-
1150
- class NinetailedPlugin {}
1151
-
1152
- const ElementSeenPayloadSchema = z.object({
1153
- element: z.any(),
1154
- experience: z.object({
1155
- id: z.string(),
1156
- type: z.union([z.literal('nt_experiment'), z.literal('nt_personalization')]),
1157
- name: z.string().optional(),
1158
- description: z.string().optional()
1159
- }).optional().nullable(),
1160
- audience: z.object({
1161
- id: z.string(),
1162
- name: z.string().optional(),
1163
- description: z.string().optional()
1164
- }).optional().nullable().default({
1165
- id: 'ALL_VISITORS',
1166
- name: 'All Visitors',
1167
- description: 'This is the default all visitors audience as no audience was set.'
1168
- }),
1169
- variant: z.object({
1170
- id: z.string()
1171
- }).catchall(z.unknown()),
1172
- variantIndex: z.number()
1173
- });
1174
-
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 };
1203
+ export { ANONYMOUS_ID, COMPONENT, COMPONENT_START, CONSENT, DEBUG_FLAG, EMPTY_MERGE_ID, EXPERIENCES_FALLBACK_CACHE, HAS_SEEN_STICKY_COMPONENT, LEGACY_ANONYMOUS_ID, Ninetailed, NinetailedCorePlugin, OnChangeEmitter, PAGE_HIDDEN, PLUGIN_NAME, PROFILE_CHANGE, PROFILE_FALLBACK_CACHE, PROFILE_RESET, SET_ENABLED_FEATURES, buildClientNinetailedRequestContext, decodeExperienceVariantsMap, makeExperienceSelectMiddleware, selectPluginsHavingExperienceSelectionMiddleware, selectPluginsHavingOnChangeEmitter, selectVariant };