@ninetailed/experience.js 3.0.0-beta.32 → 3.0.0-beta.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs +120 -100
- package/index.js +120 -101
- package/lib/Ninetailed.d.ts +17 -30
- package/lib/analytics/constants.d.ts +2 -0
- package/lib/analytics/get-analytics-plugin.d.ts +9 -16
- package/lib/experience/isExperienceMatch.d.ts +2 -2
- package/lib/experience/selectActiveExperiments.d.ts +2 -2
- package/lib/experience/selectBaselineWithVariants.d.ts +2 -2
- package/lib/experience/selectDistribution.d.ts +4 -4
- package/lib/experience/selectEligibleExperiences.d.ts +5 -5
- package/lib/experience/selectExperience.d.ts +5 -5
- package/lib/experience/selectHasVariants.d.ts +2 -2
- package/lib/experience/selectVariant.d.ts +4 -4
- package/lib/experience/selectVariants.d.ts +2 -2
- package/lib/experience/types/Baseline.d.ts +2 -3
- package/lib/experience/types/BaselineWithVariants.d.ts +4 -3
- package/lib/experience/types/ExperienceConfiguration.d.ts +3 -2
- package/lib/experience/types/Reference.d.ts +3 -0
- package/lib/experience/types/VariantRef.d.ts +4 -0
- package/lib/experience/types/index.d.ts +2 -1
- package/lib/experience/utils.d.ts +2 -2
- package/package.json +4 -3
- package/lib/experience/types/Variant.d.ts +0 -4
package/index.cjs
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var unionBy = require('lodash/unionBy');
|
|
6
6
|
var experience_jsShared = require('@ninetailed/experience.js-shared');
|
|
7
7
|
var Analytics = require('analytics');
|
|
8
|
+
var experience_jsPluginAnalytics = require('@ninetailed/experience.js-plugin-analytics');
|
|
8
9
|
var flatten = require('lodash/flatten');
|
|
9
10
|
var find = require('lodash/find');
|
|
10
11
|
var includes = require('lodash/includes');
|
|
@@ -2586,80 +2587,74 @@ const LEGACY_ANONYMOUS_ID = '__anon_id';
|
|
|
2586
2587
|
const ANONYMOUS_ID = '__nt_anonymous_id__';
|
|
2587
2588
|
const DEBUG_FLAG = '__nt_debug__';
|
|
2588
2589
|
const PROFILE_FALLBACK_CACHE = '__nt_profile__';
|
|
2590
|
+
const PROFILE_CHANGE = 'profile-change';
|
|
2591
|
+
const PROFILE_RESET = 'profile-reset';
|
|
2589
2592
|
|
|
2590
|
-
const NINETAILED_TRACKER_EVENTS = {
|
|
2591
|
-
/**
|
|
2592
|
-
* `profile` - Fires when the profile is returned by the cdp API.
|
|
2593
|
-
*/
|
|
2594
|
-
profile: 'profile',
|
|
2595
|
-
/**
|
|
2596
|
-
* `reset` - gets fired when the profile gets reset, so other plugins can react.
|
|
2597
|
-
*/
|
|
2598
|
-
reset: 'reset-profile'
|
|
2599
|
-
};
|
|
2600
2593
|
const PLUGIN_NAME = 'ninetailed';
|
|
2601
2594
|
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
2602
2595
|
const ninetailedPlugin = ({
|
|
2603
|
-
|
|
2604
|
-
environment,
|
|
2605
|
-
preview: _preview = false,
|
|
2606
|
-
url,
|
|
2596
|
+
apiClient,
|
|
2607
2597
|
profile,
|
|
2608
2598
|
locale
|
|
2609
2599
|
}) => {
|
|
2610
|
-
|
|
2611
|
-
clientId,
|
|
2612
|
-
environment,
|
|
2613
|
-
url
|
|
2614
|
-
});
|
|
2600
|
+
let _instance;
|
|
2615
2601
|
let queue = [];
|
|
2616
|
-
const flush =
|
|
2602
|
+
const flush = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2617
2603
|
const events = Object.assign([], queue);
|
|
2618
2604
|
experience_jsShared.logger.info('Start flushing events.');
|
|
2619
2605
|
queue = [];
|
|
2620
2606
|
if (!events.length) {
|
|
2621
|
-
return
|
|
2607
|
+
return {
|
|
2608
|
+
success: true
|
|
2609
|
+
};
|
|
2622
2610
|
}
|
|
2623
2611
|
try {
|
|
2624
|
-
const anonymousId =
|
|
2612
|
+
const anonymousId = _instance.storage.getItem(ANONYMOUS_ID);
|
|
2625
2613
|
const profile = yield apiClient.upsertProfile({
|
|
2626
2614
|
profileId: anonymousId,
|
|
2627
2615
|
events
|
|
2628
2616
|
}, {
|
|
2629
2617
|
locale
|
|
2630
2618
|
});
|
|
2631
|
-
|
|
2632
|
-
|
|
2619
|
+
_instance.storage.setItem(ANONYMOUS_ID, profile.id);
|
|
2620
|
+
_instance.storage.setItem(PROFILE_FALLBACK_CACHE, profile);
|
|
2633
2621
|
experience_jsShared.logger.debug('Profile from api: ', profile);
|
|
2634
|
-
|
|
2635
|
-
type:
|
|
2622
|
+
_instance.dispatch({
|
|
2623
|
+
type: PROFILE_CHANGE,
|
|
2636
2624
|
profile
|
|
2637
2625
|
});
|
|
2626
|
+
yield delay(20);
|
|
2627
|
+
return {
|
|
2628
|
+
success: true
|
|
2629
|
+
};
|
|
2638
2630
|
} catch (error) {
|
|
2639
2631
|
experience_jsShared.logger.debug('An error occurred during flushing the events: ', error);
|
|
2640
|
-
const fallbackProfile =
|
|
2632
|
+
const fallbackProfile = _instance.storage.getItem(PROFILE_FALLBACK_CACHE);
|
|
2641
2633
|
if (fallbackProfile) {
|
|
2642
2634
|
experience_jsShared.logger.debug('Found a fallback profile - will use this.');
|
|
2643
|
-
|
|
2644
|
-
type:
|
|
2635
|
+
_instance.dispatch({
|
|
2636
|
+
type: PROFILE_CHANGE,
|
|
2645
2637
|
profile: fallbackProfile
|
|
2646
2638
|
});
|
|
2639
|
+
return {
|
|
2640
|
+
success: false
|
|
2641
|
+
};
|
|
2647
2642
|
} else {
|
|
2648
2643
|
experience_jsShared.logger.debug('No fallback profile found - setting profile to null.');
|
|
2649
|
-
|
|
2650
|
-
type:
|
|
2644
|
+
_instance.dispatch({
|
|
2645
|
+
type: PROFILE_CHANGE,
|
|
2646
|
+
// TODO is it a good idea to set the profile to null?
|
|
2651
2647
|
profile: null,
|
|
2652
2648
|
error
|
|
2653
2649
|
});
|
|
2650
|
+
return {
|
|
2651
|
+
success: false
|
|
2652
|
+
};
|
|
2654
2653
|
}
|
|
2655
2654
|
}
|
|
2656
|
-
// This is necessary to make sure that the cache is updated before the next flush is performed
|
|
2657
|
-
yield delay(20);
|
|
2658
2655
|
});
|
|
2659
|
-
const
|
|
2660
|
-
const enqueueEvent = (event, instance) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2656
|
+
const enqueueEvent = event => __awaiter(void 0, void 0, void 0, function* () {
|
|
2661
2657
|
queue = unionBy__default["default"]([event], queue, 'messageId');
|
|
2662
|
-
throttledFlush(instance);
|
|
2663
2658
|
});
|
|
2664
2659
|
const abortNonClientEvents = ({
|
|
2665
2660
|
abort,
|
|
@@ -2676,6 +2671,7 @@ const ninetailedPlugin = ({
|
|
|
2676
2671
|
initialize: ({
|
|
2677
2672
|
instance
|
|
2678
2673
|
}) => {
|
|
2674
|
+
_instance = instance;
|
|
2679
2675
|
if (instance.storage.getItem(DEBUG_FLAG)) {
|
|
2680
2676
|
experience_jsShared.logger.addSink(new experience_jsShared.ConsoleLogSink());
|
|
2681
2677
|
experience_jsShared.logger.info('Ninetailed Debug Mode is enabled.');
|
|
@@ -2692,12 +2688,12 @@ const ninetailedPlugin = ({
|
|
|
2692
2688
|
}
|
|
2693
2689
|
experience_jsShared.logger.debug('Ninetailed Core plugin initialized.');
|
|
2694
2690
|
},
|
|
2691
|
+
flush: asyncThrottle(flush),
|
|
2695
2692
|
pageStart: params => {
|
|
2696
2693
|
return abortNonClientEvents(params);
|
|
2697
2694
|
},
|
|
2698
2695
|
page: ({
|
|
2699
|
-
payload
|
|
2700
|
-
instance
|
|
2696
|
+
payload
|
|
2701
2697
|
}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2702
2698
|
experience_jsShared.logger.info('Sending Page event.');
|
|
2703
2699
|
const ctx = buildClientNinetailedRequestContext();
|
|
@@ -2706,14 +2702,13 @@ const ninetailedPlugin = ({
|
|
|
2706
2702
|
timestamp: payload.meta.ts,
|
|
2707
2703
|
properties: payload.properties,
|
|
2708
2704
|
ctx
|
|
2709
|
-
})
|
|
2705
|
+
}));
|
|
2710
2706
|
}),
|
|
2711
2707
|
trackStart: params => {
|
|
2712
2708
|
return abortNonClientEvents(params);
|
|
2713
2709
|
},
|
|
2714
2710
|
track: ({
|
|
2715
|
-
payload
|
|
2716
|
-
instance
|
|
2711
|
+
payload
|
|
2717
2712
|
}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2718
2713
|
experience_jsShared.logger.info('Sending Track event.');
|
|
2719
2714
|
const ctx = buildClientNinetailedRequestContext();
|
|
@@ -2723,14 +2718,13 @@ const ninetailedPlugin = ({
|
|
|
2723
2718
|
event: payload.event,
|
|
2724
2719
|
properties: payload.properties,
|
|
2725
2720
|
ctx
|
|
2726
|
-
})
|
|
2721
|
+
}));
|
|
2727
2722
|
}),
|
|
2728
2723
|
identifyStart: params => {
|
|
2729
2724
|
return abortNonClientEvents(params);
|
|
2730
2725
|
},
|
|
2731
2726
|
identify: ({
|
|
2732
|
-
payload
|
|
2733
|
-
instance
|
|
2727
|
+
payload
|
|
2734
2728
|
}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2735
2729
|
experience_jsShared.logger.info('Sending Identify event.');
|
|
2736
2730
|
const ctx = buildClientNinetailedRequestContext();
|
|
@@ -2745,7 +2739,7 @@ const ninetailedPlugin = ({
|
|
|
2745
2739
|
traits: payload.traits,
|
|
2746
2740
|
userId: payload.userId,
|
|
2747
2741
|
ctx
|
|
2748
|
-
})
|
|
2742
|
+
}));
|
|
2749
2743
|
}),
|
|
2750
2744
|
setItemStart: ({
|
|
2751
2745
|
abort,
|
|
@@ -2762,10 +2756,10 @@ const ninetailedPlugin = ({
|
|
|
2762
2756
|
experience_jsShared.logger.debug('Resetting profile.');
|
|
2763
2757
|
const instance = args[args.length - 1];
|
|
2764
2758
|
instance.dispatch({
|
|
2765
|
-
type:
|
|
2759
|
+
type: PROFILE_RESET
|
|
2766
2760
|
});
|
|
2767
|
-
|
|
2768
|
-
|
|
2761
|
+
instance.storage.removeItem(ANONYMOUS_ID);
|
|
2762
|
+
instance.storage.removeItem(PROFILE_FALLBACK_CACHE);
|
|
2769
2763
|
experience_jsShared.logger.debug('Removed old profile data from localstorage.');
|
|
2770
2764
|
// sending a new page event, when no anonymousId is set will create a new profile.
|
|
2771
2765
|
yield instance.page();
|
|
@@ -2777,11 +2771,11 @@ const ninetailedPlugin = ({
|
|
|
2777
2771
|
const instance = args[args.length - 1];
|
|
2778
2772
|
const consoleLogSink = new experience_jsShared.ConsoleLogSink();
|
|
2779
2773
|
if (enabled) {
|
|
2780
|
-
|
|
2774
|
+
instance.storage.setItem(DEBUG_FLAG, true);
|
|
2781
2775
|
experience_jsShared.logger.addSink(consoleLogSink);
|
|
2782
2776
|
experience_jsShared.logger.info('Debug mode enabled.');
|
|
2783
2777
|
} else {
|
|
2784
|
-
|
|
2778
|
+
instance.storage.removeItem(DEBUG_FLAG);
|
|
2785
2779
|
experience_jsShared.logger.info('Debug mode disabled.');
|
|
2786
2780
|
experience_jsShared.logger.removeSink(consoleLogSink.name);
|
|
2787
2781
|
}
|
|
@@ -3188,11 +3182,7 @@ for (var COLLECTION_NAME in DOMIterables) {
|
|
|
3188
3182
|
handlePrototype(DOMTokenListPrototype, 'DOMTokenList');
|
|
3189
3183
|
|
|
3190
3184
|
class Ninetailed {
|
|
3191
|
-
constructor({
|
|
3192
|
-
clientId,
|
|
3193
|
-
environment,
|
|
3194
|
-
preview
|
|
3195
|
-
}, {
|
|
3185
|
+
constructor(ninetailedApiClientInstanceOrOptions, {
|
|
3196
3186
|
plugins,
|
|
3197
3187
|
url,
|
|
3198
3188
|
profile,
|
|
@@ -3203,47 +3193,65 @@ class Ninetailed {
|
|
|
3203
3193
|
} = {}) {
|
|
3204
3194
|
this.isInitialized = false;
|
|
3205
3195
|
this.page = (data, options) => __awaiter(this, void 0, void 0, function* () {
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3196
|
+
try {
|
|
3197
|
+
const result = experience_jsShared.PageviewProperties.partial().default({}).safeParse(data);
|
|
3198
|
+
if (!result.success) {
|
|
3199
|
+
throw new Error(`[Validation Error] "page" was called with invalid params. Page data is not valid: ${result.error.format()}`);
|
|
3200
|
+
}
|
|
3201
|
+
yield this.waitUntilInitialized();
|
|
3202
|
+
yield this.instance.page(data, this.buildOptions(options));
|
|
3203
|
+
return this.eventQueue.flush();
|
|
3204
|
+
} catch (error) {
|
|
3205
|
+
experience_jsShared.logger.error(error);
|
|
3206
|
+
if (error instanceof RangeError) {
|
|
3207
|
+
throw new Error(`[Validation Error] "page" 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.`);
|
|
3208
|
+
}
|
|
3209
|
+
throw error;
|
|
3209
3210
|
}
|
|
3210
|
-
yield this.waitUntilInitialized();
|
|
3211
|
-
return this.instance.page(data, this.buildOptions(options));
|
|
3212
3211
|
});
|
|
3213
3212
|
this.track = (event, properties, options) => __awaiter(this, void 0, void 0, function* () {
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3213
|
+
try {
|
|
3214
|
+
const result = experience_jsShared.Properties.default({}).safeParse(properties);
|
|
3215
|
+
if (!result.success) {
|
|
3216
|
+
throw new Error(`[Validation Error] "track" was called with invalid params. Properties are no valid json object: ${result.error.format()}`);
|
|
3217
|
+
}
|
|
3218
|
+
yield this.waitUntilInitialized();
|
|
3219
|
+
yield this.instance.track(event.toString(), result.data, this.buildOptions(options));
|
|
3220
|
+
return this.eventQueue.flush();
|
|
3221
|
+
} catch (error) {
|
|
3222
|
+
experience_jsShared.logger.error(error);
|
|
3223
|
+
if (error instanceof RangeError) {
|
|
3224
|
+
throw new Error(`[Validation Error] "track" 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.`);
|
|
3225
|
+
}
|
|
3226
|
+
throw error;
|
|
3217
3227
|
}
|
|
3218
|
-
yield this.waitUntilInitialized();
|
|
3219
|
-
return this.instance.track(event.toString(), properties, this.buildOptions(options));
|
|
3220
3228
|
});
|
|
3221
|
-
this.trackHasSeenComponent =
|
|
3222
|
-
return this.
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
ninetailed: false
|
|
3226
|
-
}
|
|
3227
|
-
});
|
|
3229
|
+
this.trackHasSeenComponent = properties => __awaiter(this, void 0, void 0, function* () {
|
|
3230
|
+
return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
|
|
3231
|
+
type: experience_jsPluginAnalytics.HAS_SEEN_COMPONENT
|
|
3232
|
+
}));
|
|
3228
3233
|
});
|
|
3229
|
-
this.
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
return this.track('nt_experience', sanitizedProperties, {
|
|
3234
|
-
plugins: {
|
|
3235
|
-
all: true,
|
|
3236
|
-
ninetailed: false
|
|
3237
|
-
}
|
|
3238
|
-
});
|
|
3234
|
+
this.trackHasSeenExperience = properties => {
|
|
3235
|
+
return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
|
|
3236
|
+
type: experience_jsPluginAnalytics.HAS_SEEN_EXPERIENCE
|
|
3237
|
+
}));
|
|
3239
3238
|
};
|
|
3240
3239
|
this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3240
|
+
try {
|
|
3241
|
+
const result = experience_jsShared.Traits.default({}).safeParse(traits);
|
|
3242
|
+
if (!result.success) {
|
|
3243
|
+
throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
|
|
3244
|
+
}
|
|
3245
|
+
yield this.waitUntilInitialized();
|
|
3246
|
+
yield this.instance.identify(uid.toString(), result.data, this.buildOptions(options));
|
|
3247
|
+
return this.eventQueue.flush();
|
|
3248
|
+
} catch (error) {
|
|
3249
|
+
experience_jsShared.logger.error(error);
|
|
3250
|
+
if (error instanceof RangeError) {
|
|
3251
|
+
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.`);
|
|
3252
|
+
}
|
|
3253
|
+
throw error;
|
|
3244
3254
|
}
|
|
3245
|
-
yield this.waitUntilInitialized();
|
|
3246
|
-
return this.instance.identify(uid.toString(), result.data, this.buildOptions(options));
|
|
3247
3255
|
});
|
|
3248
3256
|
this.reset = () => {
|
|
3249
3257
|
this.onIsInitialized(() => {
|
|
@@ -3261,7 +3269,7 @@ class Ninetailed {
|
|
|
3261
3269
|
};
|
|
3262
3270
|
this.onProfileChange = cb => {
|
|
3263
3271
|
cb(this.profileState);
|
|
3264
|
-
return this.instance.on(
|
|
3272
|
+
return this.instance.on(PROFILE_CHANGE, ({
|
|
3265
3273
|
payload
|
|
3266
3274
|
}) => {
|
|
3267
3275
|
if (payload.error) {
|
|
@@ -3296,6 +3304,21 @@ class Ninetailed {
|
|
|
3296
3304
|
this.onIsInitialized(resolve);
|
|
3297
3305
|
});
|
|
3298
3306
|
};
|
|
3307
|
+
if (ninetailedApiClientInstanceOrOptions instanceof experience_jsShared.NinetailedApiClient) {
|
|
3308
|
+
this.apiClient = ninetailedApiClientInstanceOrOptions;
|
|
3309
|
+
} else {
|
|
3310
|
+
const {
|
|
3311
|
+
clientId,
|
|
3312
|
+
environment,
|
|
3313
|
+
preview
|
|
3314
|
+
} = ninetailedApiClientInstanceOrOptions;
|
|
3315
|
+
this.apiClient = new experience_jsShared.NinetailedApiClient({
|
|
3316
|
+
clientId,
|
|
3317
|
+
environment,
|
|
3318
|
+
url,
|
|
3319
|
+
preview
|
|
3320
|
+
});
|
|
3321
|
+
}
|
|
3299
3322
|
this.plugins = flatten__default["default"](plugins || []);
|
|
3300
3323
|
if (profile) {
|
|
3301
3324
|
this._profileState = {
|
|
@@ -3319,17 +3342,15 @@ class Ninetailed {
|
|
|
3319
3342
|
experience_jsShared.logger.addSink(new experience_jsShared.OnErrorLogSink(onError));
|
|
3320
3343
|
}
|
|
3321
3344
|
this.logger = experience_jsShared.logger;
|
|
3345
|
+
this.eventQueue = ninetailedPlugin({
|
|
3346
|
+
apiClient: this.apiClient,
|
|
3347
|
+
profile,
|
|
3348
|
+
locale,
|
|
3349
|
+
requestTimeout
|
|
3350
|
+
});
|
|
3322
3351
|
this.instance = Analytics__default["default"]({
|
|
3323
3352
|
app: 'ninetailed',
|
|
3324
|
-
plugins: [...this.plugins,
|
|
3325
|
-
clientId,
|
|
3326
|
-
environment,
|
|
3327
|
-
url,
|
|
3328
|
-
profile,
|
|
3329
|
-
locale,
|
|
3330
|
-
requestTimeout,
|
|
3331
|
-
preview
|
|
3332
|
-
})]
|
|
3353
|
+
plugins: [...this.plugins, this.eventQueue]
|
|
3333
3354
|
});
|
|
3334
3355
|
const detachOnReadyListener = this.instance.on('ready', () => {
|
|
3335
3356
|
this.isInitialized = true;
|
|
@@ -3412,8 +3433,6 @@ const selectVariant$1 = (baseline, variants, {
|
|
|
3412
3433
|
return includes__default["default"](profile === null || profile === void 0 ? void 0 : profile.audiences, (_a = variant.audience) === null || _a === void 0 ? void 0 : _a.id);
|
|
3413
3434
|
});
|
|
3414
3435
|
if (variant) {
|
|
3415
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3416
|
-
// @ts-ignore
|
|
3417
3436
|
if ((options === null || options === void 0 ? void 0 : options.holdout) || -1 > (profile === null || profile === void 0 ? void 0 : profile.random)) {
|
|
3418
3437
|
return {
|
|
3419
3438
|
loading: false,
|
|
@@ -4303,10 +4322,11 @@ exports.ANONYMOUS_ID = ANONYMOUS_ID;
|
|
|
4303
4322
|
exports.DEBUG_FLAG = DEBUG_FLAG;
|
|
4304
4323
|
exports.EXPERIENCE_TRAIT_PREFIX = EXPERIENCE_TRAIT_PREFIX;
|
|
4305
4324
|
exports.LEGACY_ANONYMOUS_ID = LEGACY_ANONYMOUS_ID;
|
|
4306
|
-
exports.NINETAILED_TRACKER_EVENTS = NINETAILED_TRACKER_EVENTS;
|
|
4307
4325
|
exports.Ninetailed = Ninetailed;
|
|
4308
4326
|
exports.PLUGIN_NAME = PLUGIN_NAME;
|
|
4327
|
+
exports.PROFILE_CHANGE = PROFILE_CHANGE;
|
|
4309
4328
|
exports.PROFILE_FALLBACK_CACHE = PROFILE_FALLBACK_CACHE;
|
|
4329
|
+
exports.PROFILE_RESET = PROFILE_RESET;
|
|
4310
4330
|
exports.decodeExperienceVariantsMap = decodeExperienceVariantsMap;
|
|
4311
4331
|
exports.isExperienceMatch = isExperienceMatch;
|
|
4312
4332
|
exports.ninetailedPlugin = ninetailedPlugin;
|
package/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import unionBy from 'lodash/unionBy';
|
|
2
|
-
import {
|
|
2
|
+
import { logger, ConsoleLogSink, buildPageEvent, buildTrackEvent, buildIdentifyEvent, NinetailedApiClient, OnLogLogSink, OnErrorLogSink, PageviewProperties, Properties, Traits } from '@ninetailed/experience.js-shared';
|
|
3
3
|
import Analytics from 'analytics';
|
|
4
|
+
import { HAS_SEEN_EXPERIENCE, HAS_SEEN_COMPONENT } from '@ninetailed/experience.js-plugin-analytics';
|
|
4
5
|
import flatten from 'lodash/flatten';
|
|
5
6
|
import find from 'lodash/find';
|
|
6
7
|
import includes from 'lodash/includes';
|
|
@@ -2573,80 +2574,74 @@ const LEGACY_ANONYMOUS_ID = '__anon_id';
|
|
|
2573
2574
|
const ANONYMOUS_ID = '__nt_anonymous_id__';
|
|
2574
2575
|
const DEBUG_FLAG = '__nt_debug__';
|
|
2575
2576
|
const PROFILE_FALLBACK_CACHE = '__nt_profile__';
|
|
2577
|
+
const PROFILE_CHANGE = 'profile-change';
|
|
2578
|
+
const PROFILE_RESET = 'profile-reset';
|
|
2576
2579
|
|
|
2577
|
-
const NINETAILED_TRACKER_EVENTS = {
|
|
2578
|
-
/**
|
|
2579
|
-
* `profile` - Fires when the profile is returned by the cdp API.
|
|
2580
|
-
*/
|
|
2581
|
-
profile: 'profile',
|
|
2582
|
-
/**
|
|
2583
|
-
* `reset` - gets fired when the profile gets reset, so other plugins can react.
|
|
2584
|
-
*/
|
|
2585
|
-
reset: 'reset-profile'
|
|
2586
|
-
};
|
|
2587
2580
|
const PLUGIN_NAME = 'ninetailed';
|
|
2588
2581
|
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
2589
2582
|
const ninetailedPlugin = ({
|
|
2590
|
-
|
|
2591
|
-
environment,
|
|
2592
|
-
preview: _preview = false,
|
|
2593
|
-
url,
|
|
2583
|
+
apiClient,
|
|
2594
2584
|
profile,
|
|
2595
2585
|
locale
|
|
2596
2586
|
}) => {
|
|
2597
|
-
|
|
2598
|
-
clientId,
|
|
2599
|
-
environment,
|
|
2600
|
-
url
|
|
2601
|
-
});
|
|
2587
|
+
let _instance;
|
|
2602
2588
|
let queue = [];
|
|
2603
|
-
const flush =
|
|
2589
|
+
const flush = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2604
2590
|
const events = Object.assign([], queue);
|
|
2605
2591
|
logger.info('Start flushing events.');
|
|
2606
2592
|
queue = [];
|
|
2607
2593
|
if (!events.length) {
|
|
2608
|
-
return
|
|
2594
|
+
return {
|
|
2595
|
+
success: true
|
|
2596
|
+
};
|
|
2609
2597
|
}
|
|
2610
2598
|
try {
|
|
2611
|
-
const anonymousId =
|
|
2599
|
+
const anonymousId = _instance.storage.getItem(ANONYMOUS_ID);
|
|
2612
2600
|
const profile = yield apiClient.upsertProfile({
|
|
2613
2601
|
profileId: anonymousId,
|
|
2614
2602
|
events
|
|
2615
2603
|
}, {
|
|
2616
2604
|
locale
|
|
2617
2605
|
});
|
|
2618
|
-
|
|
2619
|
-
|
|
2606
|
+
_instance.storage.setItem(ANONYMOUS_ID, profile.id);
|
|
2607
|
+
_instance.storage.setItem(PROFILE_FALLBACK_CACHE, profile);
|
|
2620
2608
|
logger.debug('Profile from api: ', profile);
|
|
2621
|
-
|
|
2622
|
-
type:
|
|
2609
|
+
_instance.dispatch({
|
|
2610
|
+
type: PROFILE_CHANGE,
|
|
2623
2611
|
profile
|
|
2624
2612
|
});
|
|
2613
|
+
yield delay(20);
|
|
2614
|
+
return {
|
|
2615
|
+
success: true
|
|
2616
|
+
};
|
|
2625
2617
|
} catch (error) {
|
|
2626
2618
|
logger.debug('An error occurred during flushing the events: ', error);
|
|
2627
|
-
const fallbackProfile =
|
|
2619
|
+
const fallbackProfile = _instance.storage.getItem(PROFILE_FALLBACK_CACHE);
|
|
2628
2620
|
if (fallbackProfile) {
|
|
2629
2621
|
logger.debug('Found a fallback profile - will use this.');
|
|
2630
|
-
|
|
2631
|
-
type:
|
|
2622
|
+
_instance.dispatch({
|
|
2623
|
+
type: PROFILE_CHANGE,
|
|
2632
2624
|
profile: fallbackProfile
|
|
2633
2625
|
});
|
|
2626
|
+
return {
|
|
2627
|
+
success: false
|
|
2628
|
+
};
|
|
2634
2629
|
} else {
|
|
2635
2630
|
logger.debug('No fallback profile found - setting profile to null.');
|
|
2636
|
-
|
|
2637
|
-
type:
|
|
2631
|
+
_instance.dispatch({
|
|
2632
|
+
type: PROFILE_CHANGE,
|
|
2633
|
+
// TODO is it a good idea to set the profile to null?
|
|
2638
2634
|
profile: null,
|
|
2639
2635
|
error
|
|
2640
2636
|
});
|
|
2637
|
+
return {
|
|
2638
|
+
success: false
|
|
2639
|
+
};
|
|
2641
2640
|
}
|
|
2642
2641
|
}
|
|
2643
|
-
// This is necessary to make sure that the cache is updated before the next flush is performed
|
|
2644
|
-
yield delay(20);
|
|
2645
2642
|
});
|
|
2646
|
-
const
|
|
2647
|
-
const enqueueEvent = (event, instance) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2643
|
+
const enqueueEvent = event => __awaiter(void 0, void 0, void 0, function* () {
|
|
2648
2644
|
queue = unionBy([event], queue, 'messageId');
|
|
2649
|
-
throttledFlush(instance);
|
|
2650
2645
|
});
|
|
2651
2646
|
const abortNonClientEvents = ({
|
|
2652
2647
|
abort,
|
|
@@ -2663,6 +2658,7 @@ const ninetailedPlugin = ({
|
|
|
2663
2658
|
initialize: ({
|
|
2664
2659
|
instance
|
|
2665
2660
|
}) => {
|
|
2661
|
+
_instance = instance;
|
|
2666
2662
|
if (instance.storage.getItem(DEBUG_FLAG)) {
|
|
2667
2663
|
logger.addSink(new ConsoleLogSink());
|
|
2668
2664
|
logger.info('Ninetailed Debug Mode is enabled.');
|
|
@@ -2679,12 +2675,12 @@ const ninetailedPlugin = ({
|
|
|
2679
2675
|
}
|
|
2680
2676
|
logger.debug('Ninetailed Core plugin initialized.');
|
|
2681
2677
|
},
|
|
2678
|
+
flush: asyncThrottle(flush),
|
|
2682
2679
|
pageStart: params => {
|
|
2683
2680
|
return abortNonClientEvents(params);
|
|
2684
2681
|
},
|
|
2685
2682
|
page: ({
|
|
2686
|
-
payload
|
|
2687
|
-
instance
|
|
2683
|
+
payload
|
|
2688
2684
|
}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2689
2685
|
logger.info('Sending Page event.');
|
|
2690
2686
|
const ctx = buildClientNinetailedRequestContext();
|
|
@@ -2693,14 +2689,13 @@ const ninetailedPlugin = ({
|
|
|
2693
2689
|
timestamp: payload.meta.ts,
|
|
2694
2690
|
properties: payload.properties,
|
|
2695
2691
|
ctx
|
|
2696
|
-
})
|
|
2692
|
+
}));
|
|
2697
2693
|
}),
|
|
2698
2694
|
trackStart: params => {
|
|
2699
2695
|
return abortNonClientEvents(params);
|
|
2700
2696
|
},
|
|
2701
2697
|
track: ({
|
|
2702
|
-
payload
|
|
2703
|
-
instance
|
|
2698
|
+
payload
|
|
2704
2699
|
}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2705
2700
|
logger.info('Sending Track event.');
|
|
2706
2701
|
const ctx = buildClientNinetailedRequestContext();
|
|
@@ -2710,14 +2705,13 @@ const ninetailedPlugin = ({
|
|
|
2710
2705
|
event: payload.event,
|
|
2711
2706
|
properties: payload.properties,
|
|
2712
2707
|
ctx
|
|
2713
|
-
})
|
|
2708
|
+
}));
|
|
2714
2709
|
}),
|
|
2715
2710
|
identifyStart: params => {
|
|
2716
2711
|
return abortNonClientEvents(params);
|
|
2717
2712
|
},
|
|
2718
2713
|
identify: ({
|
|
2719
|
-
payload
|
|
2720
|
-
instance
|
|
2714
|
+
payload
|
|
2721
2715
|
}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
2722
2716
|
logger.info('Sending Identify event.');
|
|
2723
2717
|
const ctx = buildClientNinetailedRequestContext();
|
|
@@ -2732,7 +2726,7 @@ const ninetailedPlugin = ({
|
|
|
2732
2726
|
traits: payload.traits,
|
|
2733
2727
|
userId: payload.userId,
|
|
2734
2728
|
ctx
|
|
2735
|
-
})
|
|
2729
|
+
}));
|
|
2736
2730
|
}),
|
|
2737
2731
|
setItemStart: ({
|
|
2738
2732
|
abort,
|
|
@@ -2749,10 +2743,10 @@ const ninetailedPlugin = ({
|
|
|
2749
2743
|
logger.debug('Resetting profile.');
|
|
2750
2744
|
const instance = args[args.length - 1];
|
|
2751
2745
|
instance.dispatch({
|
|
2752
|
-
type:
|
|
2746
|
+
type: PROFILE_RESET
|
|
2753
2747
|
});
|
|
2754
|
-
|
|
2755
|
-
|
|
2748
|
+
instance.storage.removeItem(ANONYMOUS_ID);
|
|
2749
|
+
instance.storage.removeItem(PROFILE_FALLBACK_CACHE);
|
|
2756
2750
|
logger.debug('Removed old profile data from localstorage.');
|
|
2757
2751
|
// sending a new page event, when no anonymousId is set will create a new profile.
|
|
2758
2752
|
yield instance.page();
|
|
@@ -2764,11 +2758,11 @@ const ninetailedPlugin = ({
|
|
|
2764
2758
|
const instance = args[args.length - 1];
|
|
2765
2759
|
const consoleLogSink = new ConsoleLogSink();
|
|
2766
2760
|
if (enabled) {
|
|
2767
|
-
|
|
2761
|
+
instance.storage.setItem(DEBUG_FLAG, true);
|
|
2768
2762
|
logger.addSink(consoleLogSink);
|
|
2769
2763
|
logger.info('Debug mode enabled.');
|
|
2770
2764
|
} else {
|
|
2771
|
-
|
|
2765
|
+
instance.storage.removeItem(DEBUG_FLAG);
|
|
2772
2766
|
logger.info('Debug mode disabled.');
|
|
2773
2767
|
logger.removeSink(consoleLogSink.name);
|
|
2774
2768
|
}
|
|
@@ -3175,11 +3169,7 @@ for (var COLLECTION_NAME in DOMIterables) {
|
|
|
3175
3169
|
handlePrototype(DOMTokenListPrototype, 'DOMTokenList');
|
|
3176
3170
|
|
|
3177
3171
|
class Ninetailed {
|
|
3178
|
-
constructor({
|
|
3179
|
-
clientId,
|
|
3180
|
-
environment,
|
|
3181
|
-
preview
|
|
3182
|
-
}, {
|
|
3172
|
+
constructor(ninetailedApiClientInstanceOrOptions, {
|
|
3183
3173
|
plugins,
|
|
3184
3174
|
url,
|
|
3185
3175
|
profile,
|
|
@@ -3190,47 +3180,65 @@ class Ninetailed {
|
|
|
3190
3180
|
} = {}) {
|
|
3191
3181
|
this.isInitialized = false;
|
|
3192
3182
|
this.page = (data, options) => __awaiter(this, void 0, void 0, function* () {
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3183
|
+
try {
|
|
3184
|
+
const result = PageviewProperties.partial().default({}).safeParse(data);
|
|
3185
|
+
if (!result.success) {
|
|
3186
|
+
throw new Error(`[Validation Error] "page" was called with invalid params. Page data is not valid: ${result.error.format()}`);
|
|
3187
|
+
}
|
|
3188
|
+
yield this.waitUntilInitialized();
|
|
3189
|
+
yield this.instance.page(data, this.buildOptions(options));
|
|
3190
|
+
return this.eventQueue.flush();
|
|
3191
|
+
} catch (error) {
|
|
3192
|
+
logger.error(error);
|
|
3193
|
+
if (error instanceof RangeError) {
|
|
3194
|
+
throw new Error(`[Validation Error] "page" 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.`);
|
|
3195
|
+
}
|
|
3196
|
+
throw error;
|
|
3196
3197
|
}
|
|
3197
|
-
yield this.waitUntilInitialized();
|
|
3198
|
-
return this.instance.page(data, this.buildOptions(options));
|
|
3199
3198
|
});
|
|
3200
3199
|
this.track = (event, properties, options) => __awaiter(this, void 0, void 0, function* () {
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3200
|
+
try {
|
|
3201
|
+
const result = Properties.default({}).safeParse(properties);
|
|
3202
|
+
if (!result.success) {
|
|
3203
|
+
throw new Error(`[Validation Error] "track" was called with invalid params. Properties are no valid json object: ${result.error.format()}`);
|
|
3204
|
+
}
|
|
3205
|
+
yield this.waitUntilInitialized();
|
|
3206
|
+
yield this.instance.track(event.toString(), result.data, this.buildOptions(options));
|
|
3207
|
+
return this.eventQueue.flush();
|
|
3208
|
+
} catch (error) {
|
|
3209
|
+
logger.error(error);
|
|
3210
|
+
if (error instanceof RangeError) {
|
|
3211
|
+
throw new Error(`[Validation Error] "track" 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.`);
|
|
3212
|
+
}
|
|
3213
|
+
throw error;
|
|
3204
3214
|
}
|
|
3205
|
-
yield this.waitUntilInitialized();
|
|
3206
|
-
return this.instance.track(event.toString(), properties, this.buildOptions(options));
|
|
3207
3215
|
});
|
|
3208
|
-
this.trackHasSeenComponent =
|
|
3209
|
-
return this.
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
ninetailed: false
|
|
3213
|
-
}
|
|
3214
|
-
});
|
|
3216
|
+
this.trackHasSeenComponent = properties => __awaiter(this, void 0, void 0, function* () {
|
|
3217
|
+
return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
|
|
3218
|
+
type: HAS_SEEN_COMPONENT
|
|
3219
|
+
}));
|
|
3215
3220
|
});
|
|
3216
|
-
this.
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
return this.track('nt_experience', sanitizedProperties, {
|
|
3221
|
-
plugins: {
|
|
3222
|
-
all: true,
|
|
3223
|
-
ninetailed: false
|
|
3224
|
-
}
|
|
3225
|
-
});
|
|
3221
|
+
this.trackHasSeenExperience = properties => {
|
|
3222
|
+
return this.instance.dispatch(Object.assign(Object.assign({}, properties), {
|
|
3223
|
+
type: HAS_SEEN_EXPERIENCE
|
|
3224
|
+
}));
|
|
3226
3225
|
};
|
|
3227
3226
|
this.identify = (uid, traits, options) => __awaiter(this, void 0, void 0, function* () {
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3227
|
+
try {
|
|
3228
|
+
const result = Traits.default({}).safeParse(traits);
|
|
3229
|
+
if (!result.success) {
|
|
3230
|
+
throw new Error(`[Validation Error] "identify" was called with invalid params. Traits are no valid json: ${result.error.format()}`);
|
|
3231
|
+
}
|
|
3232
|
+
yield this.waitUntilInitialized();
|
|
3233
|
+
yield this.instance.identify(uid.toString(), result.data, this.buildOptions(options));
|
|
3234
|
+
return this.eventQueue.flush();
|
|
3235
|
+
} catch (error) {
|
|
3236
|
+
logger.error(error);
|
|
3237
|
+
if (error instanceof RangeError) {
|
|
3238
|
+
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.`);
|
|
3239
|
+
}
|
|
3240
|
+
throw error;
|
|
3231
3241
|
}
|
|
3232
|
-
yield this.waitUntilInitialized();
|
|
3233
|
-
return this.instance.identify(uid.toString(), result.data, this.buildOptions(options));
|
|
3234
3242
|
});
|
|
3235
3243
|
this.reset = () => {
|
|
3236
3244
|
this.onIsInitialized(() => {
|
|
@@ -3248,7 +3256,7 @@ class Ninetailed {
|
|
|
3248
3256
|
};
|
|
3249
3257
|
this.onProfileChange = cb => {
|
|
3250
3258
|
cb(this.profileState);
|
|
3251
|
-
return this.instance.on(
|
|
3259
|
+
return this.instance.on(PROFILE_CHANGE, ({
|
|
3252
3260
|
payload
|
|
3253
3261
|
}) => {
|
|
3254
3262
|
if (payload.error) {
|
|
@@ -3283,6 +3291,21 @@ class Ninetailed {
|
|
|
3283
3291
|
this.onIsInitialized(resolve);
|
|
3284
3292
|
});
|
|
3285
3293
|
};
|
|
3294
|
+
if (ninetailedApiClientInstanceOrOptions instanceof NinetailedApiClient) {
|
|
3295
|
+
this.apiClient = ninetailedApiClientInstanceOrOptions;
|
|
3296
|
+
} else {
|
|
3297
|
+
const {
|
|
3298
|
+
clientId,
|
|
3299
|
+
environment,
|
|
3300
|
+
preview
|
|
3301
|
+
} = ninetailedApiClientInstanceOrOptions;
|
|
3302
|
+
this.apiClient = new NinetailedApiClient({
|
|
3303
|
+
clientId,
|
|
3304
|
+
environment,
|
|
3305
|
+
url,
|
|
3306
|
+
preview
|
|
3307
|
+
});
|
|
3308
|
+
}
|
|
3286
3309
|
this.plugins = flatten(plugins || []);
|
|
3287
3310
|
if (profile) {
|
|
3288
3311
|
this._profileState = {
|
|
@@ -3306,17 +3329,15 @@ class Ninetailed {
|
|
|
3306
3329
|
logger.addSink(new OnErrorLogSink(onError));
|
|
3307
3330
|
}
|
|
3308
3331
|
this.logger = logger;
|
|
3332
|
+
this.eventQueue = ninetailedPlugin({
|
|
3333
|
+
apiClient: this.apiClient,
|
|
3334
|
+
profile,
|
|
3335
|
+
locale,
|
|
3336
|
+
requestTimeout
|
|
3337
|
+
});
|
|
3309
3338
|
this.instance = Analytics({
|
|
3310
3339
|
app: 'ninetailed',
|
|
3311
|
-
plugins: [...this.plugins,
|
|
3312
|
-
clientId,
|
|
3313
|
-
environment,
|
|
3314
|
-
url,
|
|
3315
|
-
profile,
|
|
3316
|
-
locale,
|
|
3317
|
-
requestTimeout,
|
|
3318
|
-
preview
|
|
3319
|
-
})]
|
|
3340
|
+
plugins: [...this.plugins, this.eventQueue]
|
|
3320
3341
|
});
|
|
3321
3342
|
const detachOnReadyListener = this.instance.on('ready', () => {
|
|
3322
3343
|
this.isInitialized = true;
|
|
@@ -3399,8 +3420,6 @@ const selectVariant$1 = (baseline, variants, {
|
|
|
3399
3420
|
return includes(profile === null || profile === void 0 ? void 0 : profile.audiences, (_a = variant.audience) === null || _a === void 0 ? void 0 : _a.id);
|
|
3400
3421
|
});
|
|
3401
3422
|
if (variant) {
|
|
3402
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3403
|
-
// @ts-ignore
|
|
3404
3423
|
if ((options === null || options === void 0 ? void 0 : options.holdout) || -1 > (profile === null || profile === void 0 ? void 0 : profile.random)) {
|
|
3405
3424
|
return {
|
|
3406
3425
|
loading: false,
|
|
@@ -4286,4 +4305,4 @@ const decodeExperienceVariantsMap = encodedExperienceVariantsMap => {
|
|
|
4286
4305
|
}), {});
|
|
4287
4306
|
};
|
|
4288
4307
|
|
|
4289
|
-
export { ANONYMOUS_ID, DEBUG_FLAG, EXPERIENCE_TRAIT_PREFIX, LEGACY_ANONYMOUS_ID,
|
|
4308
|
+
export { ANONYMOUS_ID, DEBUG_FLAG, EXPERIENCE_TRAIT_PREFIX, LEGACY_ANONYMOUS_ID, Ninetailed, PLUGIN_NAME, PROFILE_CHANGE, PROFILE_FALLBACK_CACHE, PROFILE_RESET, decodeExperienceVariantsMap, isExperienceMatch, ninetailedPlugin, selectActiveExperiments, selectDistribution, selectEligibleExperiences, selectExperience, selectBaselineWithVariants as selectExperienceBaselineWithVariants, selectVariant as selectExperienceVariant, selectVariants as selectExperienceVariants, selectHasVariants as selectHasExperienceVariants, selectVariant$1 as selectVariant };
|
package/lib/Ninetailed.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AnalyticsPlugin, DetachListeners } from 'analytics';
|
|
2
|
-
import { Locale, Traits, Profile,
|
|
2
|
+
import { Locale, Traits, Profile, OnLogHandler, OnErrorHandler, Logger, PageviewProperties, Properties, NinetailedApiClient, NinetailedApiClientOptions } from '@ninetailed/experience.js-shared';
|
|
3
|
+
import { TrackComponentProperties, TrackExperienceProperties } from '@ninetailed/experience.js-plugin-analytics';
|
|
4
|
+
import { FlushResult } from './analytics';
|
|
3
5
|
import { ProfileState } from './types';
|
|
4
|
-
import { ExperienceConfiguration } from './experience';
|
|
5
6
|
declare global {
|
|
6
7
|
interface Window {
|
|
7
8
|
ninetailed?: {
|
|
@@ -29,24 +30,11 @@ declare type EventFunctionOptions = {
|
|
|
29
30
|
};
|
|
30
31
|
};
|
|
31
32
|
declare type OnProfileChangeCallback = (profile: ProfileState) => void;
|
|
32
|
-
export declare type Page = (data?: Partial<PageviewProperties>, options?: EventFunctionOptions) => Promise<
|
|
33
|
-
export declare type Track = (event: string, properties?: Properties, options?: EventFunctionOptions) => Promise<
|
|
34
|
-
export declare type TrackHasSeenComponent = (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
id: string;
|
|
38
|
-
};
|
|
39
|
-
isPersonalized: boolean;
|
|
40
|
-
}) => Promise<void>;
|
|
41
|
-
export declare type TrackExperienceProperties = {
|
|
42
|
-
experience: ExperienceConfiguration;
|
|
43
|
-
variant: number;
|
|
44
|
-
component: {
|
|
45
|
-
id: string;
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
export declare type TrackExperience = (properties: TrackExperienceProperties) => Promise<void>;
|
|
49
|
-
export declare type Identify = (uid: string, traits?: Traits, options?: EventFunctionOptions) => Promise<void>;
|
|
33
|
+
export declare type Page = (data?: Partial<PageviewProperties>, options?: EventFunctionOptions) => Promise<FlushResult>;
|
|
34
|
+
export declare type Track = (event: string, properties?: Properties, options?: EventFunctionOptions) => Promise<FlushResult>;
|
|
35
|
+
export declare type TrackHasSeenComponent = (properties: TrackComponentProperties) => Promise<void>;
|
|
36
|
+
export declare type TrackHasSeenExperience = (properties: TrackExperienceProperties) => Promise<void>;
|
|
37
|
+
export declare type Identify = (uid: string, traits?: Traits, options?: EventFunctionOptions) => Promise<FlushResult>;
|
|
50
38
|
export declare type Reset = () => void;
|
|
51
39
|
export declare type Debug = (enable: boolean) => void;
|
|
52
40
|
export declare type OnProfileChange = (cb: OnProfileChangeCallback) => DetachListeners;
|
|
@@ -54,7 +42,7 @@ export interface NinetailedInstance {
|
|
|
54
42
|
page: Page;
|
|
55
43
|
track: Track;
|
|
56
44
|
trackHasSeenComponent: TrackHasSeenComponent;
|
|
57
|
-
|
|
45
|
+
trackHasSeenExperience: TrackHasSeenExperience;
|
|
58
46
|
identify: Identify;
|
|
59
47
|
reset: Reset;
|
|
60
48
|
debug: Debug;
|
|
@@ -64,22 +52,21 @@ export interface NinetailedInstance {
|
|
|
64
52
|
logger: Logger;
|
|
65
53
|
onIsInitialized: OnIsInitialized;
|
|
66
54
|
}
|
|
55
|
+
declare type NinetailedApiClientInstanceOrOptions = NinetailedApiClient | NinetailedApiClientOptions;
|
|
67
56
|
export declare class Ninetailed implements NinetailedInstance {
|
|
68
57
|
private readonly instance;
|
|
69
58
|
private _profileState;
|
|
70
59
|
private isInitialized;
|
|
60
|
+
private readonly apiClient;
|
|
61
|
+
private readonly eventQueue;
|
|
71
62
|
readonly plugins: AnalyticsPlugin[];
|
|
72
63
|
readonly logger: Logger;
|
|
73
|
-
constructor({
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
preview?: boolean;
|
|
77
|
-
}, { plugins, url, profile, locale, requestTimeout, onLog, onError, }?: Options);
|
|
78
|
-
page: (data?: Partial<PageviewProperties>, options?: EventFunctionOptions) => Promise<any>;
|
|
79
|
-
track: (event: string, properties?: Properties, options?: EventFunctionOptions) => Promise<any>;
|
|
64
|
+
constructor(ninetailedApiClientInstanceOrOptions: NinetailedApiClientInstanceOrOptions, { plugins, url, profile, locale, requestTimeout, onLog, onError, }?: Options);
|
|
65
|
+
page: (data?: Partial<PageviewProperties>, options?: EventFunctionOptions) => Promise<FlushResult>;
|
|
66
|
+
track: (event: string, properties?: Properties, options?: EventFunctionOptions) => Promise<FlushResult>;
|
|
80
67
|
trackHasSeenComponent: TrackHasSeenComponent;
|
|
81
|
-
|
|
82
|
-
identify: (uid: string, traits?: Traits, options?: EventFunctionOptions) => Promise<
|
|
68
|
+
trackHasSeenExperience: TrackHasSeenExperience;
|
|
69
|
+
identify: (uid: string, traits?: Traits, options?: EventFunctionOptions) => Promise<FlushResult>;
|
|
83
70
|
reset: () => void;
|
|
84
71
|
debug: (enabled: boolean) => void;
|
|
85
72
|
onProfileChange: (cb: OnProfileChangeCallback) => DetachListeners;
|
|
@@ -2,3 +2,5 @@ export declare const LEGACY_ANONYMOUS_ID = "__anon_id";
|
|
|
2
2
|
export declare const ANONYMOUS_ID = "__nt_anonymous_id__";
|
|
3
3
|
export declare const DEBUG_FLAG = "__nt_debug__";
|
|
4
4
|
export declare const PROFILE_FALLBACK_CACHE = "__nt_profile__";
|
|
5
|
+
export declare const PROFILE_CHANGE = "profile-change";
|
|
6
|
+
export declare const PROFILE_RESET = "profile-reset";
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import { AnalyticsPlugin } from 'analytics';
|
|
2
|
-
import { Profile, Locale } from '@ninetailed/experience.js-shared';
|
|
2
|
+
import { Profile, Locale, NinetailedApiClient } from '@ninetailed/experience.js-shared';
|
|
3
3
|
declare type AnalyticsPluginNinetailedConfig = {
|
|
4
|
-
|
|
5
|
-
environment?: string;
|
|
6
|
-
preview?: boolean;
|
|
7
|
-
url?: string;
|
|
4
|
+
apiClient: NinetailedApiClient;
|
|
8
5
|
profile?: Profile;
|
|
9
6
|
locale?: Locale;
|
|
10
7
|
requestTimeout?: number;
|
|
11
8
|
};
|
|
12
|
-
export declare const NINETAILED_TRACKER_EVENTS: {
|
|
13
|
-
/**
|
|
14
|
-
* `profile` - Fires when the profile is returned by the cdp API.
|
|
15
|
-
*/
|
|
16
|
-
profile: string;
|
|
17
|
-
/**
|
|
18
|
-
* `reset` - gets fired when the profile gets reset, so other plugins can react.
|
|
19
|
-
*/
|
|
20
|
-
reset: string;
|
|
21
|
-
};
|
|
22
9
|
export declare const PLUGIN_NAME = "ninetailed";
|
|
23
|
-
export declare
|
|
10
|
+
export declare type FlushResult = {
|
|
11
|
+
success: boolean;
|
|
12
|
+
};
|
|
13
|
+
export interface NinetailedEventQueue extends AnalyticsPlugin {
|
|
14
|
+
flush: () => Promise<FlushResult>;
|
|
15
|
+
}
|
|
16
|
+
export declare const ninetailedPlugin: ({ apiClient, profile, locale, }: AnalyticsPluginNinetailedConfig) => NinetailedEventQueue;
|
|
24
17
|
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Profile } from '@ninetailed/experience.js-shared';
|
|
2
2
|
import { ExperienceConfiguration } from './types';
|
|
3
3
|
declare type IsExperienceMatchArgs = {
|
|
4
|
-
experience: ExperienceConfiguration
|
|
5
|
-
activeExperiments: ExperienceConfiguration[];
|
|
4
|
+
experience: ExperienceConfiguration<any>;
|
|
5
|
+
activeExperiments: ExperienceConfiguration<any>[];
|
|
6
6
|
profile: Profile;
|
|
7
7
|
};
|
|
8
8
|
export declare const isExperienceMatch: ({ experience, activeExperiments, profile, }: IsExperienceMatchArgs) => boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Profile } from '@ninetailed/experience.js-shared';
|
|
2
|
-
import { ExperienceConfiguration } from './types';
|
|
3
|
-
export declare const selectActiveExperiments: (experiments: ExperienceConfiguration[], profile: Profile) => ExperienceConfiguration[];
|
|
2
|
+
import { ExperienceConfiguration, Reference } from './types';
|
|
3
|
+
export declare const selectActiveExperiments: <Variant extends Reference>(experiments: ExperienceConfiguration<Variant>[], profile: Profile) => ExperienceConfiguration<Variant>[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Baseline, BaselineWithVariants, ExperienceConfiguration } from './types';
|
|
2
|
-
export declare const selectBaselineWithVariants: (experience: ExperienceConfiguration
|
|
1
|
+
import { Baseline, BaselineWithVariants, ExperienceConfiguration, Reference } from './types';
|
|
2
|
+
export declare const selectBaselineWithVariants: <Variant extends Reference>(experience: ExperienceConfiguration<Variant>, baseline: Baseline) => BaselineWithVariants<Variant> | null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Profile } from '@ninetailed/experience.js-shared';
|
|
2
|
-
import { Distribution, ExperienceConfiguration } from './types';
|
|
3
|
-
declare type SelectDistributionArgs = {
|
|
4
|
-
experience: ExperienceConfiguration
|
|
2
|
+
import { Distribution, ExperienceConfiguration, Reference } from './types';
|
|
3
|
+
declare type SelectDistributionArgs<Variant extends Reference> = {
|
|
4
|
+
experience: ExperienceConfiguration<Variant>;
|
|
5
5
|
profile: Profile;
|
|
6
6
|
};
|
|
7
|
-
export declare const selectDistribution: ({ experience, profile, }: SelectDistributionArgs) => Distribution;
|
|
7
|
+
export declare const selectDistribution: <Variant extends Reference>({ experience, profile, }: SelectDistributionArgs<Variant>) => Distribution;
|
|
8
8
|
export {};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { ExperienceConfiguration } from './types';
|
|
2
|
-
declare type SelectEligibleExperiencesArgs = {
|
|
3
|
-
experiences: ExperienceConfiguration[];
|
|
4
|
-
activeExperiments: ExperienceConfiguration[];
|
|
1
|
+
import { ExperienceConfiguration, Reference } from './types';
|
|
2
|
+
declare type SelectEligibleExperiencesArgs<Variant extends Reference> = {
|
|
3
|
+
experiences: ExperienceConfiguration<Variant>[];
|
|
4
|
+
activeExperiments: ExperienceConfiguration<Variant>[];
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
7
|
* We can use any personalization as eligible experience
|
|
8
8
|
* When going for an experiment we can only select a active experiment when 1 or more experiments are active
|
|
9
9
|
* If the profile is not in any active experiments, we can select any expermiment
|
|
10
10
|
*/
|
|
11
|
-
export declare const selectEligibleExperiences: ({ experiences, activeExperiments, }: SelectEligibleExperiencesArgs) => ExperienceConfiguration[];
|
|
11
|
+
export declare const selectEligibleExperiences: <Variant extends Reference>({ experiences, activeExperiments, }: SelectEligibleExperiencesArgs<Variant>) => ExperienceConfiguration<Variant>[];
|
|
12
12
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Profile } from '@ninetailed/experience.js-shared';
|
|
2
|
-
import { ExperienceConfiguration } from './types';
|
|
3
|
-
declare type SelectExprienceArgs = {
|
|
4
|
-
experiences: ExperienceConfiguration[];
|
|
5
|
-
activeExperiments: ExperienceConfiguration[];
|
|
2
|
+
import { ExperienceConfiguration, Reference } from './types';
|
|
3
|
+
declare type SelectExprienceArgs<Variant extends Reference> = {
|
|
4
|
+
experiences: ExperienceConfiguration<Variant>[];
|
|
5
|
+
activeExperiments: ExperienceConfiguration<Variant>[];
|
|
6
6
|
profile: Profile;
|
|
7
7
|
};
|
|
8
|
-
export declare const selectExperience: ({ experiences, activeExperiments, profile, }: SelectExprienceArgs) => ExperienceConfiguration | null;
|
|
8
|
+
export declare const selectExperience: <Variant extends Reference>({ experiences, activeExperiments, profile, }: SelectExprienceArgs<Variant>) => ExperienceConfiguration<Variant> | null;
|
|
9
9
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Baseline, ExperienceConfiguration } from './types';
|
|
2
|
-
export declare const selectHasVariants: (experience: ExperienceConfiguration
|
|
1
|
+
import { Baseline, ExperienceConfiguration, Reference } from './types';
|
|
2
|
+
export declare const selectHasVariants: <Variant extends Reference>(experience: ExperienceConfiguration<Variant>, baseline: Baseline) => boolean;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Profile } from '@ninetailed/experience.js-shared';
|
|
2
|
-
import { Baseline, ExperienceConfiguration,
|
|
3
|
-
declare type SelectVariantArgs = {
|
|
2
|
+
import { Baseline, ExperienceConfiguration, Reference, VariantRef } from './types';
|
|
3
|
+
declare type SelectVariantArgs<Variant extends Reference> = {
|
|
4
4
|
baseline: Baseline;
|
|
5
|
-
experience: ExperienceConfiguration
|
|
5
|
+
experience: ExperienceConfiguration<Variant>;
|
|
6
6
|
profile: Profile;
|
|
7
7
|
};
|
|
8
|
-
export declare const selectVariant: ({ baseline, experience, profile, }: SelectVariantArgs) => Variant | null;
|
|
8
|
+
export declare const selectVariant: <Variant extends Reference>({ baseline, experience, profile, }: SelectVariantArgs<Variant>) => Variant | VariantRef | null;
|
|
9
9
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Baseline,
|
|
2
|
-
export declare const selectVariants: (experience: ExperienceConfiguration
|
|
1
|
+
import { Baseline, ExperienceConfiguration, Reference, VariantRef } from './types';
|
|
2
|
+
export declare const selectVariants: <Variant extends Reference>(experience: ExperienceConfiguration<Variant>, baseline: Baseline) => (Variant | VariantRef)[];
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
};
|
|
1
|
+
import { Reference } from './Reference';
|
|
2
|
+
export declare type Baseline<P = unknown> = P & Reference;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Baseline } from './Baseline';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { Reference } from './Reference';
|
|
3
|
+
import { VariantRef } from './VariantRef';
|
|
4
|
+
export declare type BaselineWithVariants<Variant extends Reference> = {
|
|
4
5
|
baseline: Baseline;
|
|
5
|
-
variants: Variant
|
|
6
|
+
variants: (Variant | VariantRef)[];
|
|
6
7
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { BaselineWithVariants } from './BaselineWithVariants';
|
|
2
2
|
import { Distribution } from './Distribution';
|
|
3
|
+
import { Reference } from './Reference';
|
|
3
4
|
export declare type ExperienceType = 'nt_personalization' | 'nt_experiment';
|
|
4
|
-
export declare type ExperienceConfiguration = {
|
|
5
|
+
export declare type ExperienceConfiguration<Variant extends Reference> = {
|
|
5
6
|
id: string;
|
|
6
7
|
type: ExperienceType;
|
|
7
8
|
audience?: {
|
|
@@ -9,5 +10,5 @@ export declare type ExperienceConfiguration = {
|
|
|
9
10
|
};
|
|
10
11
|
trafficAllocation: number;
|
|
11
12
|
distribution: Distribution[];
|
|
12
|
-
components: BaselineWithVariants[];
|
|
13
|
+
components: BaselineWithVariants<Variant>[];
|
|
13
14
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
export type { Reference } from './Reference';
|
|
1
2
|
export type { Baseline } from './Baseline';
|
|
2
|
-
export type {
|
|
3
|
+
export type { VariantRef } from './VariantRef';
|
|
3
4
|
export type { BaselineWithVariants } from './BaselineWithVariants';
|
|
4
5
|
export type { Distribution } from './Distribution';
|
|
5
6
|
export type { ExperienceConfiguration, ExperienceType, } from './ExperienceConfiguration';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Profile } from '@ninetailed/experience.js-shared';
|
|
2
2
|
import { ExperienceConfiguration } from './types';
|
|
3
|
-
export declare const getTrafficRandom: (profile: Profile, experience: ExperienceConfiguration) => number;
|
|
4
|
-
export declare const getDistributionRandom: (profile: Profile, experience: ExperienceConfiguration) => number;
|
|
3
|
+
export declare const getTrafficRandom: (profile: Profile, experience: ExperienceConfiguration<any>) => number;
|
|
4
|
+
export declare const getDistributionRandom: (profile: Profile, experience: ExperienceConfiguration<any>) => number;
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ninetailed/experience.js",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.34",
|
|
4
4
|
"module": "./index.js",
|
|
5
5
|
"main": "./index.cjs",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "./index.d.ts",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@ninetailed/experience.js-shared": "3.0.0-beta.
|
|
9
|
+
"@ninetailed/experience.js-shared": "3.0.0-beta.34",
|
|
10
10
|
"analytics": "0.8.1",
|
|
11
11
|
"lodash": "4.17.21",
|
|
12
|
-
"murmurhash-js": "1.0.0"
|
|
12
|
+
"murmurhash-js": "1.0.0",
|
|
13
|
+
"@ninetailed/experience.js-plugin-analytics": "0.0.1"
|
|
13
14
|
},
|
|
14
15
|
"peerDependencies": {}
|
|
15
16
|
}
|