@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
@@ -3,16 +3,14 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var experience_jsShared = require('@ninetailed/experience.js-shared');
6
+ var experience_jsPluginAnalytics = require('@ninetailed/experience.js-plugin-analytics');
6
7
  var Analytics = require('analytics');
7
8
  var uuid = require('uuid');
8
- var zod = require('zod');
9
9
 
10
10
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
11
 
12
12
  var Analytics__default = /*#__PURE__*/_interopDefaultLegacy(Analytics);
13
13
 
14
- const HAS_SEEN_COMPONENT = 'has_seen_component';
15
- const HAS_SEEN_ELEMENT = 'has_seen_element';
16
14
  const COMPONENT = 'component';
17
15
  const COMPONENT_START = 'componentStart';
18
16
  const PAGE_HIDDEN = 'page_hidden';
@@ -106,98 +104,87 @@ const CONSENT = '__nt-consent__';
106
104
  const SET_ENABLED_FEATURES = 'set-enabled-features';
107
105
  const EMPTY_MERGE_ID = 'nt:empty-merge-id';
108
106
 
109
- const PLUGIN_NAME = 'ninetailed';
107
+ var _a;
108
+ const PLUGIN_NAME = 'ninetailed:core';
110
109
  const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
111
- const ninetailedCorePlugin = ({
112
- apiClient,
113
- locale,
114
- ninetailed,
115
- onInitProfileId,
116
- buildClientContext
117
- }) => {
118
- let _instance;
119
- let queue = [];
120
- let enabledFeatures = Object.values(experience_jsShared.FEATURES);
121
- const buildContext = buildClientContext || buildClientNinetailedRequestContext;
122
- const flush = () => __awaiter(void 0, void 0, void 0, function* () {
123
- const events = Object.assign([], queue);
124
- experience_jsShared.logger.info('Start flushing events.');
125
- queue = [];
126
- if (!events.length) {
127
- return {
128
- success: true
129
- };
130
- }
131
- try {
132
- const anonymousId = _instance.storage.getItem(ANONYMOUS_ID);
133
- const {
134
- profile,
135
- experiences
136
- } = yield apiClient.upsertProfile({
137
- profileId: anonymousId,
138
- events
139
- }, {
140
- locale,
141
- enabledFeatures
142
- });
143
- _instance.storage.setItem(ANONYMOUS_ID, profile.id);
144
- _instance.storage.setItem(PROFILE_FALLBACK_CACHE, profile);
145
- _instance.storage.setItem(EXPERIENCES_FALLBACK_CACHE, experiences);
146
- experience_jsShared.logger.debug('Profile from api: ', profile);
147
- experience_jsShared.logger.debug('Experiences from api: ', experiences);
148
- _instance.dispatch({
149
- type: PROFILE_CHANGE,
150
- profile,
151
- experiences
152
- });
153
- yield delay(20);
154
- return {
155
- success: true
156
- };
157
- } catch (error) {
158
- experience_jsShared.logger.debug('An error occurred during flushing the events: ', error);
159
- const fallbackProfile = _instance.storage.getItem(PROFILE_FALLBACK_CACHE);
160
- const fallbackExperiences = _instance.storage.getItem(EXPERIENCES_FALLBACK_CACHE) || [];
161
- if (fallbackProfile) {
162
- experience_jsShared.logger.debug('Found a fallback profile - will use this.');
163
- _instance.dispatch({
164
- type: PROFILE_CHANGE,
165
- profile: fallbackProfile,
166
- experiences: fallbackExperiences
167
- });
168
- } else {
169
- experience_jsShared.logger.debug('No fallback profile found - setting profile to null.');
170
- _instance.dispatch({
171
- type: PROFILE_CHANGE,
172
- profile: null,
173
- experiences: fallbackExperiences,
174
- error
110
+ class NinetailedCorePlugin extends experience_jsPluginAnalytics.NinetailedAnalyticsPlugin {
111
+ constructor({
112
+ apiClient,
113
+ locale,
114
+ ninetailed,
115
+ onInitProfileId,
116
+ buildClientContext
117
+ }) {
118
+ super();
119
+ this.name = PLUGIN_NAME;
120
+ this.queue = [];
121
+ this.enabledFeatures = Object.values(experience_jsShared.FEATURES);
122
+ this.buildContext = buildClientNinetailedRequestContext;
123
+ this[_a] = ({
124
+ payload
125
+ }) => __awaiter(this, void 0, void 0, function* () {
126
+ const ctx = this.buildContext();
127
+ return this.enqueueEvent(experience_jsShared.buildComponentViewEvent({
128
+ messageId: payload.meta.rid,
129
+ timestamp: payload.meta.ts,
130
+ componentId: payload.componentId,
131
+ experienceId: payload.experienceId,
132
+ variantIndex: payload.variantIndex,
133
+ ctx
134
+ }));
135
+ });
136
+ this.methods = {
137
+ reset: (...args) => __awaiter(this, void 0, void 0, function* () {
138
+ experience_jsShared.logger.debug('Resetting profile.');
139
+ const instance = args[args.length - 1];
140
+ instance.dispatch({
141
+ type: PROFILE_RESET
175
142
  });
176
- }
177
- return {
178
- success: false
179
- };
143
+ instance.storage.removeItem(ANONYMOUS_ID);
144
+ instance.storage.removeItem(PROFILE_FALLBACK_CACHE);
145
+ instance.storage.removeItem(EXPERIENCES_FALLBACK_CACHE);
146
+ experience_jsShared.logger.debug('Removed old profile data from localstorage.');
147
+ if (typeof this.onInitProfileId === 'function') {
148
+ const profileId = yield this.onInitProfileId(undefined);
149
+ if (typeof profileId === 'string') {
150
+ instance.storage.setItem(ANONYMOUS_ID, profileId);
151
+ }
152
+ }
153
+ yield this.ninetailed.track('nt_reset');
154
+ experience_jsShared.logger.info('Profile reset successful.');
155
+ yield delay(10);
156
+ }),
157
+ debug: (...args) => __awaiter(this, void 0, void 0, function* () {
158
+ const enabled = args[0];
159
+ const instance = args[args.length - 1];
160
+ const consoleLogSink = new experience_jsShared.ConsoleLogSink();
161
+ if (enabled) {
162
+ instance.storage.setItem(DEBUG_FLAG, true);
163
+ experience_jsShared.logger.addSink(consoleLogSink);
164
+ experience_jsShared.logger.info('Debug mode enabled.');
165
+ } else {
166
+ instance.storage.removeItem(DEBUG_FLAG);
167
+ experience_jsShared.logger.info('Debug mode disabled.');
168
+ experience_jsShared.logger.removeSink(consoleLogSink.name);
169
+ }
170
+ })
171
+ };
172
+ this.flush = asyncThrottle(this._flush.bind(this));
173
+ if (onInitProfileId) {
174
+ this.onInitProfileId = onInitProfileId;
180
175
  }
181
- });
182
- const enqueueEvent = event => __awaiter(void 0, void 0, void 0, function* () {
183
- queue = experience_jsShared.unionBy([event], queue, 'messageId');
184
- });
185
- const abortNonClientEvents = ({
186
- abort,
187
- payload
188
- }) => {
189
- if (typeof window !== 'object') {
190
- return abort();
176
+ if (buildClientContext) {
177
+ this.buildContext = buildClientContext;
191
178
  }
192
- return payload;
193
- };
194
- return {
195
- name: 'ninetailed',
196
- config: {},
197
- initialize: ({
198
- instance
199
- }) => __awaiter(void 0, void 0, void 0, function* () {
200
- _instance = instance;
179
+ this.apiClient = apiClient;
180
+ this.ninetailed = ninetailed;
181
+ this.locale = locale;
182
+ }
183
+ initialize({
184
+ instance
185
+ }) {
186
+ return __awaiter(this, void 0, void 0, function* () {
187
+ this._instance = instance;
201
188
  if (instance.storage.getItem(DEBUG_FLAG)) {
202
189
  experience_jsShared.logger.addSink(new experience_jsShared.ConsoleLogSink());
203
190
  experience_jsShared.logger.info('Ninetailed Debug Mode is enabled.');
@@ -209,8 +196,8 @@ const ninetailedCorePlugin = ({
209
196
  instance.storage.setItem(ANONYMOUS_ID, legacyAnonymousId);
210
197
  instance.storage.removeItem(LEGACY_ANONYMOUS_ID);
211
198
  }
212
- if (typeof onInitProfileId === 'function') {
213
- const profileId = yield onInitProfileId(instance.storage.getItem(ANONYMOUS_ID));
199
+ if (typeof this.onInitProfileId === 'function') {
200
+ const profileId = yield this.onInitProfileId(instance.storage.getItem(ANONYMOUS_ID));
214
201
  if (typeof profileId === 'string') {
215
202
  instance.storage.setItem(ANONYMOUS_ID, profileId);
216
203
  }
@@ -218,123 +205,181 @@ const ninetailedCorePlugin = ({
218
205
  instance.on(SET_ENABLED_FEATURES, ({
219
206
  payload
220
207
  }) => {
221
- enabledFeatures = payload.features || [];
208
+ this.enabledFeatures = payload.features || [];
222
209
  });
223
210
  experience_jsShared.logger.debug('Ninetailed Core plugin initialized.');
224
- }),
225
- flush: asyncThrottle(flush),
226
- pageStart: params => {
227
- return abortNonClientEvents(params);
228
- },
229
- page: ({
230
- payload
231
- }) => __awaiter(void 0, void 0, void 0, function* () {
211
+ });
212
+ }
213
+ pageStart(params) {
214
+ return this.abortNonClientEvents(params);
215
+ }
216
+ page({
217
+ payload
218
+ }) {
219
+ return __awaiter(this, void 0, void 0, function* () {
232
220
  experience_jsShared.logger.info('Sending Page event.');
233
- const ctx = buildContext();
234
- return enqueueEvent(experience_jsShared.buildPageEvent({
221
+ const ctx = this.buildContext();
222
+ return this.enqueueEvent(experience_jsShared.buildPageEvent({
235
223
  messageId: payload.meta.rid,
236
224
  timestamp: payload.meta.ts,
237
225
  properties: payload.properties,
238
226
  ctx
239
227
  }));
240
- }),
241
- trackStart: params => {
242
- return abortNonClientEvents(params);
243
- },
244
- track: ({
245
- payload
246
- }) => __awaiter(void 0, void 0, void 0, function* () {
228
+ });
229
+ }
230
+ trackStart(params) {
231
+ return this.abortNonClientEvents(params);
232
+ }
233
+ track({
234
+ payload
235
+ }) {
236
+ return __awaiter(this, void 0, void 0, function* () {
247
237
  experience_jsShared.logger.info('Sending Track event.');
248
- const ctx = buildContext();
249
- return enqueueEvent(experience_jsShared.buildTrackEvent({
238
+ const ctx = this.buildContext();
239
+ return this.enqueueEvent(experience_jsShared.buildTrackEvent({
250
240
  messageId: payload.meta.rid,
251
241
  timestamp: payload.meta.ts,
252
242
  event: payload.event,
253
243
  properties: payload.properties,
254
244
  ctx
255
245
  }));
256
- }),
257
- identifyStart: params => {
258
- return abortNonClientEvents(params);
259
- },
260
- identify: ({
261
- payload
262
- }) => __awaiter(void 0, void 0, void 0, function* () {
246
+ });
247
+ }
248
+ identifyStart(params) {
249
+ return this.abortNonClientEvents(params);
250
+ }
251
+ identify({
252
+ payload
253
+ }) {
254
+ return __awaiter(this, void 0, void 0, function* () {
263
255
  experience_jsShared.logger.info('Sending Identify event.');
264
- const ctx = buildContext();
256
+ const ctx = this.buildContext();
265
257
  if (payload.userId === EMPTY_MERGE_ID && (!payload.traits || typeof payload.traits === 'object' && Object.keys(payload.traits).length === 0)) {
266
258
  experience_jsShared.logger.info('Skipping Identify event as no userId and no traits are set.');
267
259
  return;
268
260
  }
269
- return enqueueEvent(experience_jsShared.buildIdentifyEvent({
261
+ return this.enqueueEvent(experience_jsShared.buildIdentifyEvent({
270
262
  messageId: payload.meta.rid,
271
263
  timestamp: payload.meta.ts,
272
264
  traits: payload.traits,
273
265
  userId: payload.userId === EMPTY_MERGE_ID ? '' : payload.userId,
274
266
  ctx
275
267
  }));
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
- }),
291
- setItemStart: ({
292
- abort,
293
- payload
294
- }) => {
295
- if (![ANONYMOUS_ID, DEBUG_FLAG, PROFILE_FALLBACK_CACHE, EXPERIENCES_FALLBACK_CACHE, CONSENT].includes(payload.key)) {
296
- return abort();
268
+ });
269
+ }
270
+ getComponentViewTrackingThreshold() {
271
+ return 0;
272
+ }
273
+ onTrackExperience(properties) {
274
+ return __awaiter(this, void 0, void 0, function* () {
275
+ if (properties.experience.sticky) {
276
+ yield this.instance.dispatch({
277
+ type: HAS_SEEN_STICKY_COMPONENT,
278
+ componentId: properties.selectedVariant.id,
279
+ experienceId: properties.experience.id,
280
+ variantIndex: properties.selectedVariantIndex
281
+ });
282
+ this.flush();
297
283
  }
298
- return payload;
299
- },
300
- methods: {
301
- reset: (...args) => __awaiter(void 0, void 0, void 0, function* () {
302
- experience_jsShared.logger.debug('Resetting profile.');
303
- const instance = args[args.length - 1];
304
- instance.dispatch({
305
- type: PROFILE_RESET
284
+ return Promise.resolve();
285
+ });
286
+ }
287
+ onTrackComponent() {
288
+ return Promise.resolve();
289
+ }
290
+ setItemStart({
291
+ abort,
292
+ payload
293
+ }) {
294
+ if (![ANONYMOUS_ID, DEBUG_FLAG, PROFILE_FALLBACK_CACHE, EXPERIENCES_FALLBACK_CACHE, CONSENT].includes(payload.key)) {
295
+ return abort();
296
+ }
297
+ return payload;
298
+ }
299
+ enqueueEvent(event) {
300
+ return __awaiter(this, void 0, void 0, function* () {
301
+ this.queue = experience_jsShared.unionBy([event], this.queue, 'messageId');
302
+ });
303
+ }
304
+ abortNonClientEvents({
305
+ abort,
306
+ payload
307
+ }) {
308
+ if (typeof window !== 'object') {
309
+ return abort();
310
+ }
311
+ return payload;
312
+ }
313
+ get instance() {
314
+ if (!this._instance) {
315
+ throw new Error('Ninetailed Core plugin not initialized.');
316
+ }
317
+ return this._instance;
318
+ }
319
+ _flush() {
320
+ return __awaiter(this, void 0, void 0, function* () {
321
+ const events = Object.assign([], this.queue);
322
+ experience_jsShared.logger.info('Start flushing events.');
323
+ this.queue = [];
324
+ if (!events.length) {
325
+ return {
326
+ success: true
327
+ };
328
+ }
329
+ try {
330
+ const anonymousId = this.instance.storage.getItem(ANONYMOUS_ID);
331
+ const {
332
+ profile,
333
+ experiences
334
+ } = yield this.apiClient.upsertProfile({
335
+ profileId: anonymousId,
336
+ events
337
+ }, {
338
+ locale: this.locale,
339
+ enabledFeatures: this.enabledFeatures
306
340
  });
307
- instance.storage.removeItem(ANONYMOUS_ID);
308
- instance.storage.removeItem(PROFILE_FALLBACK_CACHE);
309
- instance.storage.removeItem(EXPERIENCES_FALLBACK_CACHE);
310
- experience_jsShared.logger.debug('Removed old profile data from localstorage.');
311
- if (typeof onInitProfileId === 'function') {
312
- const profileId = yield onInitProfileId(undefined);
313
- if (typeof profileId === 'string') {
314
- instance.storage.setItem(ANONYMOUS_ID, profileId);
315
- }
316
- }
317
- yield ninetailed.track('nt_reset');
318
- experience_jsShared.logger.info('Profile reset successful.');
319
- yield delay(10);
320
- }),
321
- debug: (...args) => __awaiter(void 0, void 0, void 0, function* () {
322
- const enabled = args[0];
323
- const instance = args[args.length - 1];
324
- const consoleLogSink = new experience_jsShared.ConsoleLogSink();
325
- if (enabled) {
326
- instance.storage.setItem(DEBUG_FLAG, true);
327
- experience_jsShared.logger.addSink(consoleLogSink);
328
- experience_jsShared.logger.info('Debug mode enabled.');
341
+ this.instance.storage.setItem(ANONYMOUS_ID, profile.id);
342
+ this.instance.storage.setItem(PROFILE_FALLBACK_CACHE, profile);
343
+ this.instance.storage.setItem(EXPERIENCES_FALLBACK_CACHE, experiences);
344
+ experience_jsShared.logger.debug('Profile from api: ', profile);
345
+ experience_jsShared.logger.debug('Experiences from api: ', experiences);
346
+ this.instance.dispatch({
347
+ type: PROFILE_CHANGE,
348
+ profile,
349
+ experiences
350
+ });
351
+ yield delay(20);
352
+ return {
353
+ success: true
354
+ };
355
+ } catch (error) {
356
+ experience_jsShared.logger.debug('An error occurred during flushing the events: ', error);
357
+ const fallbackProfile = this.instance.storage.getItem(PROFILE_FALLBACK_CACHE);
358
+ const fallbackExperiences = this.instance.storage.getItem(EXPERIENCES_FALLBACK_CACHE) || [];
359
+ if (fallbackProfile) {
360
+ experience_jsShared.logger.debug('Found a fallback profile - will use this.');
361
+ this.instance.dispatch({
362
+ type: PROFILE_CHANGE,
363
+ profile: fallbackProfile,
364
+ experiences: fallbackExperiences
365
+ });
329
366
  } else {
330
- instance.storage.removeItem(DEBUG_FLAG);
331
- experience_jsShared.logger.info('Debug mode disabled.');
332
- experience_jsShared.logger.removeSink(consoleLogSink.name);
367
+ experience_jsShared.logger.debug('No fallback profile found - setting profile to null.');
368
+ this.instance.dispatch({
369
+ type: PROFILE_CHANGE,
370
+ profile: null,
371
+ experiences: fallbackExperiences,
372
+ error
373
+ });
333
374
  }
334
- })
335
- }
336
- };
337
- };
375
+ return {
376
+ success: false
377
+ };
378
+ }
379
+ });
380
+ }
381
+ }
382
+ _a = HAS_SEEN_STICKY_COMPONENT;
338
383
 
339
384
  class ElementSeenObserver {
340
385
  constructor(_options) {
@@ -352,23 +397,29 @@ class ElementSeenObserver {
352
397
  target
353
398
  } = entry;
354
399
  if (isIntersecting) {
355
- const delay = this._elementDelays.get(target);
356
- const timeOut = window.setTimeout(() => {
357
- this._options.onElementSeen(target);
358
- }, delay);
359
- this._intersectionTimers.set(target, timeOut);
400
+ const delays = this._elementDelays.get(target);
401
+ delays === null || delays === void 0 ? void 0 : delays.forEach(delay => {
402
+ const timeOut = window.setTimeout(() => {
403
+ this._options.onElementSeen(target, delay);
404
+ }, delay);
405
+ const currentTimers = this._intersectionTimers.get(target) || [];
406
+ this._intersectionTimers.set(target, [...currentTimers, timeOut]);
407
+ });
360
408
  } else {
361
- const timeOut = this._intersectionTimers.get(target);
362
- if (typeof timeOut !== 'undefined') {
363
- window.clearTimeout(timeOut);
364
- }
409
+ const timeOuts = this._intersectionTimers.get(target);
410
+ timeOuts === null || timeOuts === void 0 ? void 0 : timeOuts.forEach(timeOut => {
411
+ if (typeof timeOut !== 'undefined') {
412
+ window.clearTimeout(timeOut);
413
+ }
414
+ });
365
415
  }
366
416
  });
367
417
  }
368
418
  observe(element, options) {
369
- var _a, _b;
370
- this._elementDelays.set(element, (_a = options === null || options === void 0 ? void 0 : options.delay) !== null && _a !== void 0 ? _a : 2000);
371
- (_b = this._intersectionObserver) === null || _b === void 0 ? void 0 : _b.observe(element);
419
+ var _a;
420
+ const delays = this._elementDelays.get(element) || [];
421
+ this._elementDelays.set(element, Array.from(new Set([...delays, (options === null || options === void 0 ? void 0 : options.delay) || 0])));
422
+ (_a = this._intersectionObserver) === null || _a === void 0 ? void 0 : _a.observe(element);
372
423
  }
373
424
  unobserve(element) {
374
425
  var _a;
@@ -544,6 +595,10 @@ class EventBuilder {
544
595
  }
545
596
  }
546
597
 
598
+ const hasComponentViewTrackingThreshold = arg => {
599
+ return typeof arg === 'object' && arg !== null && 'getComponentViewTrackingThreshold' in arg && typeof arg['getComponentViewTrackingThreshold'] === 'function';
600
+ };
601
+
547
602
  const buildOverrideMiddleware = experienceSelectionMiddleware => _a => {
548
603
  var {
549
604
  experience: originalExperience,
@@ -694,12 +749,12 @@ class Ninetailed {
694
749
  */
695
750
  this.trackHasSeenComponent = properties => __awaiter(this, void 0, void 0, function* () {
696
751
  return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
697
- type: HAS_SEEN_COMPONENT
752
+ type: experience_jsPluginAnalytics.HAS_SEEN_COMPONENT
698
753
  }));
699
754
  });
700
755
  this.trackComponentView = properties => {
701
756
  return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
702
- type: HAS_SEEN_ELEMENT
757
+ type: experience_jsPluginAnalytics.HAS_SEEN_ELEMENT
703
758
  }));
704
759
  };
705
760
  this.observeElement = (payload, options) => {
@@ -714,21 +769,35 @@ class Ninetailed {
714
769
  experience_jsShared.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.`);
715
770
  } else {
716
771
  this.observedElements.set(element, remaingPayload);
717
- this.elementSeenObserver.observe(element, Object.assign({
718
- delay: this.componentViewTrackingThreshold
719
- }, options));
772
+ const delays = this.pluginsWithCustomComponentViewThreshold.map(plugin => plugin.getComponentViewTrackingThreshold());
773
+ const uniqueDelays = Array.from(new Set([...delays, (options === null || options === void 0 ? void 0 : options.delay) || this.componentViewTrackingThreshold]));
774
+ uniqueDelays.forEach(delay => {
775
+ this.elementSeenObserver.observe(element, {
776
+ delay
777
+ });
778
+ });
720
779
  }
721
780
  };
722
781
  this.unobserveElement = element => {
723
782
  this.observedElements.delete(element);
724
783
  this.elementSeenObserver.unobserve(element);
725
784
  };
726
- this.onElementSeen = element => {
785
+ this.onElementSeen = (element, delay) => {
727
786
  const payload = this.observedElements.get(element);
728
787
  if (typeof payload !== 'undefined') {
729
- this.trackComponentView(Object.assign({
730
- element
731
- }, payload));
788
+ const pluginNamesInterestedInSeenElementMessage = [...this.pluginsWithCustomComponentViewThreshold.filter(plugin => plugin.getComponentViewTrackingThreshold() === delay), ...this.plugins.filter(plugin => !hasComponentViewTrackingThreshold(plugin))].map(plugin => plugin.name);
789
+ if (pluginNamesInterestedInSeenElementMessage.length === 0) {
790
+ return;
791
+ }
792
+ this.instance.dispatch(Object.assign(Object.assign({}, payload), {
793
+ element,
794
+ type: experience_jsPluginAnalytics.HAS_SEEN_ELEMENT,
795
+ plugins: Object.assign({
796
+ all: false
797
+ }, pluginNamesInterestedInSeenElementMessage.reduce((acc, curr) => Object.assign(Object.assign({}, acc), {
798
+ [curr]: true
799
+ }), {}))
800
+ }));
732
801
  }
733
802
  };
734
803
  this.reset = () => __awaiter(this, void 0, void 0, function* () {
@@ -898,7 +967,7 @@ class Ninetailed {
898
967
  const {
899
968
  variants
900
969
  } = baselineVariants;
901
- const variant = variants[selectedExperience.variantIndex - 1];
970
+ const variant = [baseline, ...variants][selectedExperience.variantIndex];
902
971
  if (!variant) {
903
972
  setSelectedVariant(overrideResult(Object.assign(Object.assign({}, emptyReturn), {
904
973
  loading: false,
@@ -996,7 +1065,7 @@ class Ninetailed {
996
1065
  }
997
1066
  this.eventBuilder = new EventBuilder(buildClientContext);
998
1067
  this.logger = experience_jsShared.logger;
999
- this.ninetailedCorePlugin = ninetailedCorePlugin({
1068
+ this.ninetailedCorePlugin = new NinetailedCorePlugin({
1000
1069
  apiClient: this.apiClient,
1001
1070
  locale,
1002
1071
  requestTimeout,
@@ -1036,6 +1105,9 @@ class Ninetailed {
1036
1105
  }
1037
1106
  this.registerWindowHandlers();
1038
1107
  }
1108
+ get pluginsWithCustomComponentViewThreshold() {
1109
+ return [this.ninetailedCorePlugin, ...this.plugins].filter(plugin => hasComponentViewTrackingThreshold(plugin));
1110
+ }
1039
1111
  get profileState() {
1040
1112
  return this._profileState;
1041
1113
  }
@@ -1144,41 +1216,6 @@ const selectVariant = (baseline, variants, {
1144
1216
  };
1145
1217
  };
1146
1218
 
1147
- const TrackComponentProperties = zod.z.object({
1148
- variant: zod.z.object({
1149
- id: zod.z.string()
1150
- }),
1151
- audience: zod.z.object({
1152
- id: zod.z.string()
1153
- }),
1154
- isPersonalized: zod.z.boolean()
1155
- });
1156
-
1157
- class NinetailedPlugin {}
1158
-
1159
- const ElementSeenPayloadSchema = zod.z.object({
1160
- element: zod.z.any(),
1161
- experience: zod.z.object({
1162
- id: zod.z.string(),
1163
- type: zod.z.union([zod.z.literal('nt_experiment'), zod.z.literal('nt_personalization')]),
1164
- name: zod.z.string().optional(),
1165
- description: zod.z.string().optional()
1166
- }).optional().nullable(),
1167
- audience: zod.z.object({
1168
- id: zod.z.string(),
1169
- name: zod.z.string().optional(),
1170
- description: zod.z.string().optional()
1171
- }).optional().nullable().default({
1172
- id: 'ALL_VISITORS',
1173
- name: 'All Visitors',
1174
- description: 'This is the default all visitors audience as no audience was set.'
1175
- }),
1176
- variant: zod.z.object({
1177
- id: zod.z.string()
1178
- }).catchall(zod.z.unknown()),
1179
- variantIndex: zod.z.number()
1180
- });
1181
-
1182
1219
  Object.defineProperty(exports, 'EXPERIENCE_TRAIT_PREFIX', {
1183
1220
  enumerable: true,
1184
1221
  get: function () { return experience_jsShared.EXPERIENCE_TRAIT_PREFIX; }
@@ -1222,13 +1259,10 @@ exports.CONSENT = CONSENT;
1222
1259
  exports.DEBUG_FLAG = DEBUG_FLAG;
1223
1260
  exports.EMPTY_MERGE_ID = EMPTY_MERGE_ID;
1224
1261
  exports.EXPERIENCES_FALLBACK_CACHE = EXPERIENCES_FALLBACK_CACHE;
1225
- exports.ElementSeenPayloadSchema = ElementSeenPayloadSchema;
1226
- exports.HAS_SEEN_COMPONENT = HAS_SEEN_COMPONENT;
1227
- exports.HAS_SEEN_ELEMENT = HAS_SEEN_ELEMENT;
1228
1262
  exports.HAS_SEEN_STICKY_COMPONENT = HAS_SEEN_STICKY_COMPONENT;
1229
1263
  exports.LEGACY_ANONYMOUS_ID = LEGACY_ANONYMOUS_ID;
1230
1264
  exports.Ninetailed = Ninetailed;
1231
- exports.NinetailedPlugin = NinetailedPlugin;
1265
+ exports.NinetailedCorePlugin = NinetailedCorePlugin;
1232
1266
  exports.OnChangeEmitter = OnChangeEmitter;
1233
1267
  exports.PAGE_HIDDEN = PAGE_HIDDEN;
1234
1268
  exports.PLUGIN_NAME = PLUGIN_NAME;
@@ -1236,11 +1270,9 @@ exports.PROFILE_CHANGE = PROFILE_CHANGE;
1236
1270
  exports.PROFILE_FALLBACK_CACHE = PROFILE_FALLBACK_CACHE;
1237
1271
  exports.PROFILE_RESET = PROFILE_RESET;
1238
1272
  exports.SET_ENABLED_FEATURES = SET_ENABLED_FEATURES;
1239
- exports.TrackComponentProperties = TrackComponentProperties;
1240
1273
  exports.buildClientNinetailedRequestContext = buildClientNinetailedRequestContext;
1241
1274
  exports.decodeExperienceVariantsMap = decodeExperienceVariantsMap;
1242
1275
  exports.makeExperienceSelectMiddleware = makeExperienceSelectMiddleware;
1243
- exports.ninetailedCorePlugin = ninetailedCorePlugin;
1244
1276
  exports.selectPluginsHavingExperienceSelectionMiddleware = selectPluginsHavingExperienceSelectionMiddleware;
1245
1277
  exports.selectPluginsHavingOnChangeEmitter = selectPluginsHavingOnChangeEmitter;
1246
1278
  exports.selectVariant = selectVariant;