From 997735ea534d1e102f7dbdb53b145597bcc553ac Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 6 Sep 2023 04:58:05 +0000 Subject: [PATCH 01/26] don't mutate props argument to .track() --- src/mixpanel-core.js | 2 +- tests/test.js | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index e6e00759..6a212d10 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -818,7 +818,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event diff --git a/tests/test.js b/tests/test.js index e2a91ad5..5f777a28 100644 --- a/tests/test.js +++ b/tests/test.js @@ -371,7 +371,7 @@ }); }); - asyncTest("check no property name aliasing occurs during minify", 1, function() { + test("check no property name aliasing occurs during minify", 1, function() { var ob = {}; var letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; _.each(letters, function(l1) { @@ -384,10 +384,8 @@ var expect_ob = _.extend({}, ob); expect_ob.token = this.token; - mixpanel.test.track('test', ob, function(response) { - deepEqual(ob, expect_ob, 'Nothing strange happened to properties'); - start(); - }); + data = mixpanel.test.track('test', ob); + ok(contains_obj(data.properties, expect_ob), 'Nothing strange happened to properties'); }); test("token property does not override configured token", 1, function() { @@ -398,6 +396,15 @@ same(data.properties.token, mixpanel.test.get_config('token'), 'Property did not override token'); }); + test("tracking does not mutate properties argument", 3, function() { + var props = {foo: 'bar', token: 'baz'}; + var data = mixpanel.test.track('test', props); + + same(props.token, 'baz', 'original properties object was not mutated'); + same(data.properties.token, mixpanel.test.get_config('token')); + same(data.properties.foo, 'bar'); + }); + asyncTest("callback doesn't override", 1, function() { var result = []; mixpanel.test.track('test', {}, function(response) { From 3f0891ec962fefcfd14ee233d67503b3b287954e Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 13 Sep 2023 23:31:41 +0000 Subject: [PATCH 02/26] WIP reload props from persistence when tracking --- src/mixpanel-people.js | 7 ++++--- src/mixpanel-persistence.js | 40 ++++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/mixpanel-people.js b/src/mixpanel-people.js index 4fc666eb..91fb0421 100644 --- a/src/mixpanel-people.js +++ b/src/mixpanel-people.js @@ -384,11 +384,12 @@ MixpanelPeople.prototype._enqueue = function(data) { MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -410,8 +411,6 @@ MixpanelPeople.prototype._flush = function( _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -421,6 +420,7 @@ MixpanelPeople.prototype._flush = function( // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -442,6 +442,7 @@ MixpanelPeople.prototype._flush = function( } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { diff --git a/src/mixpanel-persistence.js b/src/mixpanel-persistence.js index ca4e4f62..d0ea55ae 100644 --- a/src/mixpanel-persistence.js +++ b/src/mixpanel-persistence.js @@ -72,6 +72,9 @@ var MixpanelPersistence = function(config) { MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -148,6 +151,7 @@ MixpanelPersistence.prototype.upgrade = function(config) { MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -159,6 +163,17 @@ MixpanelPersistence.prototype.save = function() { ); }; +MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; +}; + +MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; +}; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -182,6 +197,8 @@ MixpanelPersistence.prototype.register_once = function(props, default_value, day if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -203,8 +220,8 @@ MixpanelPersistence.prototype.register = function(props, days) { if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -213,6 +230,7 @@ MixpanelPersistence.prototype.register = function(props, days) { }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -243,6 +261,7 @@ MixpanelPersistence.prototype.get_referrer_info = function() { // does not override any properties defined in both // returns the passed in object MixpanelPersistence.prototype.safe_merge = function(props) { + this.load(); _.each(this['props'], function(val, prop) { if (!(prop in props)) { props[prop] = val; @@ -395,7 +414,7 @@ MixpanelPersistence.prototype._add_to_people_queue = function(queue, data) { }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -411,11 +430,13 @@ MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { delete q[k]; } }, this); - - this.save(); } }; +MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); +}; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -436,25 +457,20 @@ MixpanelPersistence.prototype._get_queue_key = function(queue) { } }; -MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; -}; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; From 1eaf569b57e9835eefba9399a9c839c16249c642 Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 13 Sep 2023 23:32:55 +0000 Subject: [PATCH 03/26] rm unused method --- src/mixpanel-persistence.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/mixpanel-persistence.js b/src/mixpanel-persistence.js index d0ea55ae..7e7dc3f7 100644 --- a/src/mixpanel-persistence.js +++ b/src/mixpanel-persistence.js @@ -257,20 +257,6 @@ MixpanelPersistence.prototype.get_referrer_info = function() { }); }; -// safely fills the passed in object with stored properties, -// does not override any properties defined in both -// returns the passed in object -MixpanelPersistence.prototype.safe_merge = function(props) { - this.load(); - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; -}; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); From d2af8254d2f7338e251c04ff40e66a6659088a8d Mon Sep 17 00:00:00 2001 From: teddddd Date: Thu, 14 Sep 2023 23:41:03 +0000 Subject: [PATCH 04/26] don't send events from Chrome-Lighthouse --- src/utils.js | 1 + tests/test.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils.js b/src/utils.js index f5acbb57..b7b64925 100644 --- a/src/utils.js +++ b/src/utils.js @@ -902,6 +902,7 @@ var BLOCKED_UA_STRS = [ 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', diff --git a/tests/test.js b/tests/test.js index 5f777a28..ea9a9c48 100644 --- a/tests/test.js +++ b/tests/test.js @@ -3462,7 +3462,8 @@ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36 Google Favicon", "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko; googleweblight) Chrome/38.0.1025.166 Mobile Safari/535.19", "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012; Storebot-Google/1.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36", - "Screaming Frog SEO Spider/12.3" + "Screaming Frog SEO Spider/12.3", + "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4695.0 Mobile Safari/537.36 Chrome-Lighthouse" ]; _.each(bot_user_agents, function(ua) { ok(mixpanel._.isBlockedUA(ua), ua); From 5e5b8c96589577794095670198b4e859333acbc0 Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 19 Sep 2023 05:10:35 +0000 Subject: [PATCH 05/26] stop trying to send batches during opt-out --- src/mixpanel-core.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index 6a212d10..0bf40d22 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -667,6 +667,7 @@ MixpanelLib.prototype.init_batchers = function() { }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -1717,9 +1718,11 @@ MixpanelLib.prototype._gdpr_update_persistence = function(options) { } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; From cb498ee5c07f05375686d13c112eb02e7c137f1b Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 19 Sep 2023 23:09:00 +0000 Subject: [PATCH 06/26] attempt to clear out request-batcher queues when localStorage is failing on init --- src/mixpanel-core.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index 0bf40d22..fd4f2a5d 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -284,6 +284,10 @@ MixpanelLib.prototype._init = function(token, config, name) { if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window.addEventListener) { @@ -631,12 +635,21 @@ MixpanelLib.prototype.are_batchers_initialized = function() { return !!this.request_batchers.events; }; +MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/track/', queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/engage/', queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/groups/', queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; +} + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -655,10 +668,11 @@ MixpanelLib.prototype.init_batchers = function() { } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { From 3ce1e3542a3a33aa4032c792625b991510a2e8a3 Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 20 Sep 2023 23:44:35 +0000 Subject: [PATCH 07/26] add api_routes config option --- src/mixpanel-core.js | 16 ++++++++++++---- src/mixpanel-group.js | 2 +- src/mixpanel-people.js | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index fd4f2a5d..487c662c 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -81,11 +81,18 @@ if (navigator['sendBeacon']) { }; } +var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/', +}; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -637,10 +644,11 @@ MixpanelLib.prototype.are_batchers_initialized = function() { MixpanelLib.prototype.get_batcher_configs = function() { var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); this._batcher_configs = this._batcher_configs || { - events: {type: 'events', endpoint: '/track/', queue_key: queue_prefix + '_ev'}, - people: {type: 'people', endpoint: '/engage/', queue_key: queue_prefix + '_pp'}, - groups: {type: 'groups', endpoint: '/groups/', queue_key: queue_prefix + '_gr'} + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} }; return this._batcher_configs; } @@ -879,7 +887,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options diff --git a/src/mixpanel-group.js b/src/mixpanel-group.js index daf93e12..66735cec 100644 --- a/src/mixpanel-group.js +++ b/src/mixpanel-group.js @@ -146,7 +146,7 @@ MixpanelGroup.prototype._send_request = function(data, callback) { return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; diff --git a/src/mixpanel-people.js b/src/mixpanel-people.js index 91fb0421..a94e5507 100644 --- a/src/mixpanel-people.js +++ b/src/mixpanel-people.js @@ -348,7 +348,7 @@ MixpanelPeople.prototype._send_request = function(data, callback) { return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; From 23cbbadc8da8364108655ce24d1259dcd09680da Mon Sep 17 00:00:00 2001 From: teddddd Date: Thu, 21 Sep 2023 00:03:17 +0000 Subject: [PATCH 08/26] config docs for api options + rebuild docs --- .../javascript-full-api-reference.md | 32 ++++++++++++++++++- src/mixpanel-core.js | 10 ++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/doc/readme.io/javascript-full-api-reference.md b/doc/readme.io/javascript-full-api-reference.md index d6e1c08e..c5007e28 100644 --- a/doc/readme.io/javascript-full-api-reference.md +++ b/doc/readme.io/javascript-full-api-reference.md @@ -262,7 +262,7 @@ mixpanel.library_name.track(...); | Argument | Type | Description | | ------------- | ------------- | ----- | | **token** | String
required | Your Mixpanel API token | -| **config** | Object
optional | A dictionary of config options to override. See a list of default config options. | +| **config** | Object
optional | A dictionary of config options to override. See a list of default config options. | | **name** | String
optional | The name for the new mixpanel instance that you want created | @@ -523,10 +523,20 @@ The default config is: // secure, meaning they will only be transmitted over https secure_cookie: false + // disables enriching user profiles with first touch marketing data + skip_first_touch_marketing: false + // the amount of time track_links will // wait for Mixpanel's servers to respond track_links_timeout: 300 + // adds any UTM parameters and click IDs present on the page to any events fired + track_marketing: true + + // enables automatic page view tracking using default page view events through + // the track_pageview() method + track_pageview: false + // if you set upgrade to be true, the library will check for // a cookie from our old js library and import super // properties from it, then the old cookie is deleted @@ -684,6 +694,26 @@ If you pass a function in as the properties argument, the function will receive | **properties** | Object or Function
optional | A properties object or function that returns a dictionary of properties when passed a DOMElement | +___ +## mixpanel.track_pageview +Track a default Mixpanel page view event, which includes extra default event properties to improve page view data. The config.track_pageview option for mixpanel.init() may be turned on for tracking page loads automatically. + + + + +| Argument | Type | Description | +| ------------- | ------------- | ----- | +| **properties** | Object
optional | An optional set of additional properties to send with the page view event | +| **options** | Object
optional | Page view tracking options | +| **options.event_name** | String
optional |
    +
  • Alternate name for the tracking event
  • +
| +#### Returns: +| Type | Description | +| ----- | ------------- | +| Boolean or Object | If the tracking request was successfully initiated/queued, an object with the tracking payload sent to the API server is returned; otherwise false. | + + ___ ## mixpanel.track_with_groups Track an event with specific groups. diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index 487c662c..9a8b1a36 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -1484,6 +1484,16 @@ MixpanelLib.prototype.name_tag = function(name_tag) { * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * From c77b373cd137b0fa4d4b2128e65cac4a867b62c1 Mon Sep 17 00:00:00 2001 From: teddddd Date: Thu, 21 Sep 2023 17:54:05 +0000 Subject: [PATCH 09/26] lint --- src/mixpanel-core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index 9a8b1a36..5bc9d824 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -651,7 +651,7 @@ MixpanelLib.prototype.get_batcher_configs = function() { groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} }; return this._batcher_configs; -} +}; MixpanelLib.prototype.init_batchers = function() { if (!this.are_batchers_initialized()) { From ad4e7d3530c30685d2bd5832042faff7d3ca038f Mon Sep 17 00:00:00 2001 From: teddddd Date: Thu, 21 Sep 2023 22:09:31 +0000 Subject: [PATCH 10/26] export DEFAULT_API_ROUTES on mixpanel object --- src/mixpanel-core.js | 63 ++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index 5bc9d824..f63650d8 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -1956,37 +1956,38 @@ MixpanelLib.prototype.report_error = function(msg, err) { // EXPORTS (for closure compiler) // MixpanelLib Exports -MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; -MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; -MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; -MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; -MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; -MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; -MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; -MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; -MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; -MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; -MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; -MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; -MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; -MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; -MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; -MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; -MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; -MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; -MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; -MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; -MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; -MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; -MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; -MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; -MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; -MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; -MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; -MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; -MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; -MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; -MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; +MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; +MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; +MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; +MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; +MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; +MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; +MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; +MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; +MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; +MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; +MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; +MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; +MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; +MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; +MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; +MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; +MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; +MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; +MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; +MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; +MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; +MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; +MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; +MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; +MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; +MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; +MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; +MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; +MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; +MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; From e9e2837f10cd963e11ec7e81fa493558b90b375a Mon Sep 17 00:00:00 2001 From: teddddd Date: Thu, 21 Sep 2023 23:43:03 +0000 Subject: [PATCH 11/26] explanatory comment around opt-in/batch-start behavior --- src/mixpanel-core.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index f63650d8..1b52bcba 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -1752,6 +1752,8 @@ MixpanelLib.prototype._gdpr_update_persistence = function(options) { if (disabled) { this.stop_batch_senders(); } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time if (this._batchers_were_started) { this.start_batch_senders(); } From 49d551619bbad3112e145d0c370591fd7f9a31e3 Mon Sep 17 00:00:00 2001 From: teddddd Date: Fri, 22 Sep 2023 20:29:30 +0000 Subject: [PATCH 12/26] lint --- src/mixpanel-core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index 1b52bcba..e712f7e8 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -84,7 +84,7 @@ if (navigator['sendBeacon']) { var DEFAULT_API_ROUTES = { 'track': 'track/', 'engage': 'engage/', - 'groups': 'groups/', + 'groups': 'groups/' }; /* From 2fc85717a3545cd920501fc38690f17be8c2a8a3 Mon Sep 17 00:00:00 2001 From: teddddd Date: Fri, 22 Sep 2023 20:31:16 +0000 Subject: [PATCH 13/26] v2.48.0-rc1 --- dist/mixpanel.amd.js | 186 +++++++++++++--------- dist/mixpanel.cjs.js | 186 +++++++++++++--------- dist/mixpanel.globals.js | 186 +++++++++++++--------- dist/mixpanel.min.js | 203 +++++++++++++------------ dist/mixpanel.umd.js | 186 +++++++++++++--------- examples/commonjs-browserify/bundle.js | 186 +++++++++++++--------- examples/es2015-babelify/bundle.js | 125 ++++++++++----- examples/umd-webpack/bundle.js | 186 +++++++++++++--------- src/config.js | 2 +- 9 files changed, 870 insertions(+), 576 deletions(-) diff --git a/dist/mixpanel.amd.js b/dist/mixpanel.amd.js index dafe242c..7e9ed517 100644 --- a/dist/mixpanel.amd.js +++ b/dist/mixpanel.amd.js @@ -2,7 +2,7 @@ define(function () { 'use strict'; var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -904,6 +904,7 @@ define(function () { 'use strict'; 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', @@ -3132,7 +3133,7 @@ define(function () { 'use strict'; return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3493,7 +3494,7 @@ define(function () { 'use strict'; return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3529,11 +3530,12 @@ define(function () { 'use strict'; MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3555,8 +3557,6 @@ define(function () { 'use strict'; _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3566,6 +3566,7 @@ define(function () { 'use strict'; // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -3587,6 +3588,7 @@ define(function () { 'use strict'; } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { @@ -3685,6 +3687,9 @@ define(function () { 'use strict'; MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -3761,6 +3766,7 @@ define(function () { 'use strict'; MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -3772,6 +3778,17 @@ define(function () { 'use strict'; ); }; + MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; + }; + + MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; + }; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3795,6 +3812,8 @@ define(function () { 'use strict'; if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3816,8 +3835,8 @@ define(function () { 'use strict'; if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -3826,6 +3845,7 @@ define(function () { 'use strict'; }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3852,19 +3872,6 @@ define(function () { 'use strict'; }); }; - // safely fills the passed in object with stored properties, - // does not override any properties defined in both - // returns the passed in object - MixpanelPersistence.prototype.safe_merge = function(props) { - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; - }; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -4008,7 +4015,7 @@ define(function () { 'use strict'; }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -4024,11 +4031,13 @@ define(function () { 'use strict'; delete q[k]; } }, this); - - this.save(); } }; + MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); + }; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -4049,25 +4058,20 @@ define(function () { 'use strict'; } }; - MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; - }; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4138,11 +4142,18 @@ define(function () { 'use strict'; }; } + var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' + }; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -4341,6 +4352,10 @@ define(function () { 'use strict'; if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window$1.addEventListener) { @@ -4688,12 +4703,22 @@ define(function () { 'use strict'; return !!this.request_batchers.events; }; + MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; + }; + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -4712,10 +4737,11 @@ define(function () { 'use strict'; } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -4724,6 +4750,7 @@ define(function () { 'use strict'; }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -4875,7 +4902,7 @@ define(function () { 'use strict'; } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -4921,7 +4948,7 @@ define(function () { 'use strict'; var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -5518,6 +5545,16 @@ define(function () { 'use strict'; * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -5774,9 +5811,13 @@ define(function () { 'use strict'; } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -5978,37 +6019,38 @@ define(function () { 'use strict'; // EXPORTS (for closure compiler) // MixpanelLib Exports - MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; - MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; - MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; - MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; - MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; - MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; - MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; - MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; - MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; - MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; - MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; - MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; - MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; - MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; - MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; - MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; - MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; - MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; - MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; - MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; - MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; - MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; - MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; - MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; - MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; - MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; - MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; - MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; - MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; - MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; - MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; + MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; + MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; + MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; + MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; + MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; + MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; + MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; + MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; + MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; + MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; + MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; + MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; + MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; + MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; + MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; + MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; + MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; + MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; + MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; + MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; + MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; + MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; + MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; + MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; + MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; + MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; + MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; + MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; + MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; + MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; diff --git a/dist/mixpanel.cjs.js b/dist/mixpanel.cjs.js index a5c6bc67..8595ed50 100644 --- a/dist/mixpanel.cjs.js +++ b/dist/mixpanel.cjs.js @@ -2,7 +2,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -904,6 +904,7 @@ var BLOCKED_UA_STRS = [ 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', @@ -3132,7 +3133,7 @@ MixpanelGroup.prototype._send_request = function(data, callback) { return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3493,7 +3494,7 @@ MixpanelPeople.prototype._send_request = function(data, callback) { return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3529,11 +3530,12 @@ MixpanelPeople.prototype._enqueue = function(data) { MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3555,8 +3557,6 @@ MixpanelPeople.prototype._flush = function( _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3566,6 +3566,7 @@ MixpanelPeople.prototype._flush = function( // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -3587,6 +3588,7 @@ MixpanelPeople.prototype._flush = function( } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { @@ -3685,6 +3687,9 @@ var MixpanelPersistence = function(config) { MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -3761,6 +3766,7 @@ MixpanelPersistence.prototype.upgrade = function(config) { MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -3772,6 +3778,17 @@ MixpanelPersistence.prototype.save = function() { ); }; +MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; +}; + +MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; +}; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3795,6 +3812,8 @@ MixpanelPersistence.prototype.register_once = function(props, default_value, day if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3816,8 +3835,8 @@ MixpanelPersistence.prototype.register = function(props, days) { if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -3826,6 +3845,7 @@ MixpanelPersistence.prototype.register = function(props, days) { }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3852,19 +3872,6 @@ MixpanelPersistence.prototype.get_referrer_info = function() { }); }; -// safely fills the passed in object with stored properties, -// does not override any properties defined in both -// returns the passed in object -MixpanelPersistence.prototype.safe_merge = function(props) { - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; -}; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -4008,7 +4015,7 @@ MixpanelPersistence.prototype._add_to_people_queue = function(queue, data) { }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -4024,11 +4031,13 @@ MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { delete q[k]; } }, this); - - this.save(); } }; +MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); +}; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -4049,25 +4058,20 @@ MixpanelPersistence.prototype._get_queue_key = function(queue) { } }; -MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; -}; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4138,11 +4142,18 @@ if (navigator['sendBeacon']) { }; } +var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' +}; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -4341,6 +4352,10 @@ MixpanelLib.prototype._init = function(token, config, name) { if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window$1.addEventListener) { @@ -4688,12 +4703,22 @@ MixpanelLib.prototype.are_batchers_initialized = function() { return !!this.request_batchers.events; }; +MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; +}; + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -4712,10 +4737,11 @@ MixpanelLib.prototype.init_batchers = function() { } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -4724,6 +4750,7 @@ MixpanelLib.prototype.init_batchers = function() { }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -4875,7 +4902,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -4921,7 +4948,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -5518,6 +5545,16 @@ MixpanelLib.prototype.name_tag = function(name_tag) { * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -5774,9 +5811,13 @@ MixpanelLib.prototype._gdpr_update_persistence = function(options) { } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -5978,37 +6019,38 @@ MixpanelLib.prototype.report_error = function(msg, err) { // EXPORTS (for closure compiler) // MixpanelLib Exports -MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; -MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; -MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; -MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; -MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; -MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; -MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; -MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; -MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; -MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; -MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; -MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; -MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; -MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; -MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; -MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; -MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; -MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; -MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; -MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; -MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; -MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; -MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; -MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; -MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; -MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; -MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; -MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; -MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; -MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; -MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; +MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; +MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; +MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; +MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; +MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; +MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; +MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; +MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; +MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; +MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; +MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; +MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; +MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; +MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; +MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; +MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; +MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; +MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; +MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; +MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; +MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; +MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; +MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; +MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; +MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; +MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; +MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; +MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; +MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; +MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; diff --git a/dist/mixpanel.globals.js b/dist/mixpanel.globals.js index ddb8877a..0782310a 100644 --- a/dist/mixpanel.globals.js +++ b/dist/mixpanel.globals.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -905,6 +905,7 @@ 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', @@ -3133,7 +3134,7 @@ return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3494,7 +3495,7 @@ return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3530,11 +3531,12 @@ MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3556,8 +3558,6 @@ _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3567,6 +3567,7 @@ // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -3588,6 +3589,7 @@ } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { @@ -3686,6 +3688,9 @@ MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -3762,6 +3767,7 @@ MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -3773,6 +3779,17 @@ ); }; + MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; + }; + + MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; + }; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3796,6 +3813,8 @@ if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3817,8 +3836,8 @@ if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -3827,6 +3846,7 @@ }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3853,19 +3873,6 @@ }); }; - // safely fills the passed in object with stored properties, - // does not override any properties defined in both - // returns the passed in object - MixpanelPersistence.prototype.safe_merge = function(props) { - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; - }; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -4009,7 +4016,7 @@ }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -4025,11 +4032,13 @@ delete q[k]; } }, this); - - this.save(); } }; + MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); + }; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -4050,25 +4059,20 @@ } }; - MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; - }; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4139,11 +4143,18 @@ }; } + var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' + }; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -4342,6 +4353,10 @@ if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window$1.addEventListener) { @@ -4689,12 +4704,22 @@ return !!this.request_batchers.events; }; + MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; + }; + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -4713,10 +4738,11 @@ } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -4725,6 +4751,7 @@ }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -4876,7 +4903,7 @@ } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -4922,7 +4949,7 @@ var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -5519,6 +5546,16 @@ * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -5775,9 +5812,13 @@ } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -5979,37 +6020,38 @@ // EXPORTS (for closure compiler) // MixpanelLib Exports - MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; - MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; - MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; - MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; - MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; - MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; - MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; - MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; - MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; - MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; - MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; - MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; - MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; - MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; - MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; - MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; - MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; - MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; - MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; - MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; - MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; - MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; - MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; - MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; - MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; - MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; - MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; - MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; - MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; - MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; - MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; + MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; + MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; + MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; + MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; + MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; + MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; + MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; + MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; + MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; + MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; + MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; + MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; + MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; + MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; + MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; + MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; + MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; + MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; + MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; + MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; + MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; + MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; + MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; + MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; + MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; + MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; + MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; + MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; + MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; + MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; diff --git a/dist/mixpanel.min.js b/dist/mixpanel.min.js index 458b7853..3a3378ad 100644 --- a/dist/mixpanel.min.js +++ b/dist/mixpanel.min.js @@ -1,106 +1,107 @@ (function() { var l=void 0,m=!0,q=null,D=!1; -(function(){function Aa(){function a(){if(!a.sc)la=a.sc=m,ma=D,c.a(F,function(a){a.gc()})}function b(){try{u.documentElement.doScroll("left")}catch(d){setTimeout(b,1);return}a()}if(u.addEventListener)"complete"===u.readyState?a():u.addEventListener("DOMContentLoaded",a,D);else if(u.attachEvent){u.attachEvent("onreadystatechange",a);var d=D;try{d=x.frameElement===q}catch(f){}u.documentElement.doScroll&&d&&b()}c.Ib(x,"load",a,m)}function Ba(){y.init=function(a,b,d){if(d)return y[d]||(y[d]=F[d]=S(a, -b,d),y[d].ea()),y[d];d=y;if(F.mixpanel)d=F.mixpanel;else if(a)d=S(a,b,"mixpanel"),d.ea(),F.mixpanel=d;y=d;1===ca&&(x.mixpanel=y);Ca()}}function Ca(){c.a(F,function(a,b){"mixpanel"!==b&&(y[b]=a)});y._=c}function da(a){a=c.e(a)?a:c.g(a)?{}:{days:a};return c.extend({},Da,a)}function S(a,b,d){var f,h="mixpanel"===d?y:y[d];if(h&&0===ca)f=h;else{if(h&&!c.isArray(h)){p.error("You have already initialized "+d);return}f=new e}f.$a={};f.T(a,b,d);f.people=new j;f.people.T(f);if(!f.c("skip_first_touch_marketing")){var a= -c.info.ha(q),g={},s=D;c.a(a,function(a,b){(g["initial_"+b]=a)&&(s=m)});s&&f.people.Z(g)}J=J||f.c("debug");!c.g(h)&&c.isArray(h)&&(f.wa.call(f.people,h.people),f.wa(h));return f}function e(){}function P(){}function Ea(a){return a}function n(a){this.props={};this.qd=D;this.name=a.persistence_name?"mp_"+a.persistence_name:"mp_"+a.token+"_mixpanel";var b=a.persistence;if("cookie"!==b&&"localStorage"!==b)p.H("Unknown persistence type "+b+"; falling back to cookie"),b=a.persistence="cookie";this.i="localStorage"=== -b&&c.localStorage.oa()?c.localStorage:c.cookie;this.load();this.bc(a);this.md(a);this.save()}function j(){}function t(){}function C(a,b){this.I=b.I;this.W=new G(a,{I:c.bind(this.h,this),i:b.i});this.A=b.A;this.Qc=b.Rc;this.fa=b.fa;this.$c=b.ad;this.C=this.A.batch_size;this.la=this.A.batch_flush_interval_ms;this.qa=!this.A.batch_autostart;this.Ga=0;this.F={}}function na(a,b){var d=[];c.a(a,function(a){var c=a.id;if(c in b){if(c=b[c],c!==q)a.payload=c,d.push(a)}else d.push(a)});return d}function oa(a, -b){var d=[];c.a(a,function(a){a.id&&!b[a.id]&&d.push(a)});return d}function G(a,b){b=b||{};this.K=a;this.i=b.i||window.localStorage;this.h=b.I||c.bind(pa.error,pa);this.Ra=new qa(a,{i:this.i});this.pa=b.pa||q;this.G=[]}function qa(a,b){b=b||{};this.K=a;this.i=b.i||window.localStorage;this.Gb=b.Gb||100;this.Vb=b.Vb||2E3}function T(){this.Db="submit"}function L(){this.Db="click"}function E(){}function ra(a){var b=Fa,d=a.split("."),d=d[d.length-1];if(4a?"0"+a:a}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())};c.ra=function(a){var b={};c.a(a,function(a,f){c.Qa(a)&&0=i;)h()}function d(){var a,b,d="",c;if('"'=== +(function(){function Aa(){function a(){if(!a.zc)la=a.zc=m,ma=D,c.a(F,function(a){a.mc()})}function b(){try{u.documentElement.doScroll("left")}catch(d){setTimeout(b,1);return}a()}if(u.addEventListener)"complete"===u.readyState?a():u.addEventListener("DOMContentLoaded",a,D);else if(u.attachEvent){u.attachEvent("onreadystatechange",a);var d=D;try{d=w.frameElement===q}catch(f){}u.documentElement.doScroll&&d&&b()}c.Pb(w,"load",a,m)}function Ba(){y.init=function(a,b,d){if(d)return y[d]||(y[d]=F[d]=S(a, +b,d),y[d].ga()),y[d];d=y;if(F.mixpanel)d=F.mixpanel;else if(a)d=S(a,b,"mixpanel"),d.ga(),F.mixpanel=d;y=d;1===ca&&(w.mixpanel=y);Ca()}}function Ca(){c.a(F,function(a,b){"mixpanel"!==b&&(y[b]=a)});y._=c}function da(a){a=c.e(a)?a:c.g(a)?{}:{days:a};return c.extend({},Da,a)}function S(a,b,d){var f,h="mixpanel"===d?y:y[d];if(h&&0===ca)f=h;else{if(h&&!c.isArray(h)){o.error("You have already initialized "+d);return}f=new e}f.gb={};f.U(a,b,d);f.people=new j;f.people.U(f);if(!f.c("skip_first_touch_marketing")){var a= +c.info.ja(q),g={},s=D;c.a(a,function(a,b){(g["initial_"+b]=a)&&(s=m)});s&&f.people.aa(g)}J=J||f.c("debug");!c.g(h)&&c.isArray(h)&&(f.xa.call(f.people,h.people),f.xa(h));return f}function e(){}function P(){}function Ea(a){return a}function n(a){this.props={};this.vd=D;this.name=a.persistence_name?"mp_"+a.persistence_name:"mp_"+a.token+"_mixpanel";var b=a.persistence;if("cookie"!==b&&"localStorage"!==b)o.H("Unknown persistence type "+b+"; falling back to cookie"),b=a.persistence="cookie";this.i="localStorage"=== +b&&c.localStorage.pa()?c.localStorage:c.cookie;this.load();this.gc(a);this.rd(a);this.save()}function j(){}function t(){}function C(a,b){this.I=b.I;this.X=new G(a,{I:c.bind(this.h,this),i:b.i});this.A=b.A;this.Vc=b.Wc;this.ha=b.ha;this.ed=b.fd;this.C=this.A.batch_size;this.ma=this.A.batch_flush_interval_ms;this.ra=!this.A.batch_autostart;this.Ha=0;this.F={}}function na(a,b){var d=[];c.a(a,function(a){var c=a.id;if(c in b){if(c=b[c],c!==q)a.payload=c,d.push(a)}else d.push(a)});return d}function oa(a, +b){var d=[];c.a(a,function(a){a.id&&!b[a.id]&&d.push(a)});return d}function G(a,b){b=b||{};this.L=a;this.i=b.i||window.localStorage;this.h=b.I||c.bind(pa.error,pa);this.Ua=new qa(a,{i:this.i});this.qa=b.qa||q;this.G=[]}function qa(a,b){b=b||{};this.L=a;this.i=b.i||window.localStorage;this.Nb=b.Nb||100;this.$b=b.$b||2E3}function T(){this.Kb="submit"}function L(){this.Kb="click"}function E(){}function ra(a){var b=Fa,d=a.split("."),d=d[d.length-1];if(4a?"0"+a:a}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())};c.sa=function(a){var b={};c.a(a,function(a,f){c.Sa(a)&&0=i;)h()}function d(){var a,b,d="",c;if('"'=== i)for(;h();){if('"'===i)return h(),d;if("\\"===i)if(h(),"u"===i){for(b=c=0;4>b;b+=1){a=parseInt(h(),16);if(!isFinite(a))break;c=16*c+a}d+=String.fromCharCode(c)}else if("string"===typeof e[i])d+=e[i];else break;else d+=i}g("Bad string")}function c(){var a;a="";"-"===i&&(a="-",h("-"));for(;"0"<=i&&"9">=i;)a+=i,h();if("."===i)for(a+=".";h()&&"0"<=i&&"9">=i;)a+=i;if("e"===i||"E"===i){a+=i;h();if("-"===i||"+"===i)a+=i,h();for(;"0"<=i&&"9">=i;)a+=i,h()}a=+a;if(isFinite(a))return a;g("Bad number")}function h(a){a&& -a!==i&&g("Expected '"+a+"' instead of '"+i+"'");i=r.charAt(s);s+=1;return i}function g(a){a=new SyntaxError(a);a.pd=s;a.text=r;throw a;}var s,i,e={'"':'"',"\\":"\\","/":"/",b:"\u0008",f:"\u000c",n:"\n",r:"\r",t:"\t"},r,o;o=function(){b();switch(i){case "{":var e;a:{var s,k={};if("{"===i){h("{");b();if("}"===i){h("}");e=k;break a}for(;i;){s=d();b();h(":");Object.hasOwnProperty.call(k,s)&&g('Duplicate key "'+s+'"');k[s]=o();b();if("}"===i){h("}");e=k;break a}h(",");b()}}g("Bad object")}return e;case "[":a:{e= -[];if("["===i){h("[");b();if("]"===i){h("]");s=e;break a}for(;i;){e.push(o());b();if("]"===i){h("]");s=e;break a}h(",");b()}}g("Bad array")}return s;case '"':return d();case "-":return c();default:return"0"<=i&&"9">=i?c():a()}};return function(a){r=a;s=0;i=" ";a=o();b();i&&g("Syntax error");return a}}();c.nc=function(a){var b,d,f,h,g=0,e=0,i="",i=[];if(!a)return a;a=c.nd(a);do b=a.charCodeAt(g++),d=a.charCodeAt(g++),f=a.charCodeAt(g++),h=b<<16|d<<8|f,b=h>>18&63,d=h>>12&63,f=h>>6&63,h&=63,i[e++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+ -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h);while(ge?c++:i=127e?String.fromCharCode(e>>6|192,e&63|128):String.fromCharCode(e>>12|224,e>>6&63|128,e&63|128);i!==q&&(c>d&&(b+=a.substring(d,c)),b+=i,d=c=g+1)}c>d&&(b+=a.substring(d,a.length));return b};c.Za=function(){function a(){function a(b,d){var c,f=0;for(c=0;c=i?c():a()}};return function(a){r=a;s=0;i=" ";a=p();b();i&&g("Syntax error");return a}}();c.uc=function(a){var b,d,f,h,g=0,e=0,i="",i=[];if(!a)return a;a=c.sd(a);do b=a.charCodeAt(g++),d=a.charCodeAt(g++),f=a.charCodeAt(g++),h=b<<16|d<<8|f,b=h>>18&63,d=h>>12&63,f=h>>6&63,h&=63,i[e++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h);while(ge?c++:i=127e?String.fromCharCode(e>>6|192,e&63|128):String.fromCharCode(e>>12|224,e>>6&63|128,e&63|128);i!==q&&(c>d&&(b+=a.substring(d,c)),b+=i,d=c=g+1)}c>d&&(b+=a.substring(d,a.length));return b};c.eb=function(){function a(){function a(b,d){var c,f=0;for(c=0;cv?(Qa.error("Timeout waiting for mutex on "+o+"; clearing lock. ["+k+"]"),j.removeItem(u),j.removeItem(p),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},w*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=q);var k=c||(new Date).getTime()+"|"+Math.random(),r=(new Date).getTime(),o=this.K,w= -this.Gb,v=this.Vb,j=this.i,n=o+":X",p=o+":Y",u=o+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(t){b&&b(t)}};var pa=ga("batch");G.prototype.Ja=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.Ra.Ya(c.bind(function(){var b;try{var c=this.X();c.push(f);(b=this.Ua(c))&&this.G.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock",a);d&&d(D)},this),this.pa)};G.prototype.tc= -function(a){var b=this.G.slice(0,a);if(b.lengthg.flushAfter&&!f[g.id]&&(g.Hc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Kc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.G=oa(this.G,d);var f=c.bind(function(){var b;try{var c=this.X(),c=oa(c,d);if(b=this.Ua(c))for(var c=this.X(),f=0;fe.length)this.Y();else{this.Kb=m;var i=c.bind(function(e){this.Kb= -D;try{var g=D;if(a.$b)this.W.ld(s);else if(c.e(e)&&"timeout"===e.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(e)&&e.N&&(500<=e.N.status||429===e.N.status||"timeout"===e.error)){var i=2*this.la,k=e.N.responseHeaders;if(k){var j=k["Retry-After"];j&&(i=1E3*parseInt(j,10)||i)}i=Math.min(6E5,i);this.h("Error; retry in "+i+" ms");this.Mb(i)}else if(c.e(e)&&e.N&&413===e.N.status)if(1=v.timeout?"timeout":"Bad HTTP status: "+v.status+" "+v.statusText,n.l(a),e&&(k?e({status:0,error:a,N:v}):e(0))};v.send(j)}catch(y){n.l(y),h=D}else j=u.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,t=u.getElementsByTagName("script")[0],t.parentNode.insertBefore(j,t);return h};e.prototype.wa=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))}, -b)}var d,e=[],h=[],g=[];c.a(a,function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this):c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.hb=function(){return!!this.p.ka};e.prototype.Ac=function(){var a=this.c("token");if(!this.hb()){var b=c.bind(function(b){return new C("__mpq_"+a+b.Ta,{A:this.config,Rc:c.bind(function(a,c,e){this.k(this.c("api_host")+ -b.D,this.ab(a),c,this.cb(e,a))},this),fa:c.bind(function(a){return this.fb("before_send_"+b.type,a)},this),I:this.c("error_reporter"),ad:c.bind(this.Ub,this)})},this);this.p={ka:b({type:"events",D:"/track/",Ta:"_ev"}),Ic:b({type:"people",D:"/engage/",Ta:"_pp"}),yc:b({type:"groups",D:"/groups/",Ta:"_gr"})}}this.c("batch_autostart")&&this.Tb()};e.prototype.Tb=function(){if(this.hb())this.P=m,c.a(this.p,function(a){a.start()})};e.prototype.Ub=function(){this.P=D;c.a(this.p,function(a){a.stop();a.clear()})}; -e.prototype.push=function(a){this.wa([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.Q.qc=m:this.ta=this.ta.concat(a)};e.prototype.ab=function(a){a=c.ba(a);"base64"===this.c("api_payload_format")&&(a=c.nc(a));return{data:a}};e.prototype.Ca=function(a,b){var d=c.truncate(a.data,255),e=a.D,h=a.Ea,g=a.Zc,j=a.Sc||{},b=b||P,i=m,k=c.bind(function(){j.Sb||(d=this.fb("before_send_"+a.type,d));return d?(p.log("MIXPANEL REQUEST:"),p.log(d),this.k(e,this.ab(d),j,this.cb(b,d))):q},this);this.P&& -!g?h.Ja(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=M(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=q);var d=d||{},h=d.transport;if(h)d.Wa=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.g(a))this.l("No event name provided to mixpanel.track");else if(this.bb(a))e(0);else{b=b||{};b.token=this.c("token");var g=this.persistence.Lc(a);c.g(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3)));this.gb();g=this.c("track_marketing")?c.info.Ec():{};b=c.extend({}, -c.info.V(),g,this.persistence.V(),this.M,b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Ca({type:"events",data:{event:a,properties:b},D:this.c("api_host")+"/track/",Ea:this.p.ka,Zc:h,Sc:d},e)}});e.prototype.Xc=M(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.kc=M(function(a,b,c){var e=this.s(a);if(e===l){var h={};h[a]=[b];this.m(h)}else-1=== -e.indexOf(b)&&(e.push(b),this.m(h));return this.people.$(a,b,c)});e.prototype.Mc=M(function(a,b,c){var e=this.s(a);if(e!==l){var h=e.indexOf(b);-1(y.__SV||0)?p.H("Version mismatch; please ensure you're using the latest version of the Mixpanel code snippet."):(c.a(y._i,function(a){a&&c.isArray(a)&&(F[a[a.length-1]]=S.apply(this,a))}),Ba(),y.init(),c.a(F,function(a){a.ea()}),Aa())})()})(); +q;c.localStorage={pa:function(a){(a=U(q,a))||o.error("localStorage unsupported; falling back to cookie store");return a},error:function(a){o.error("localStorage error: "+a)},get:function(a){try{return window.localStorage.getItem(a)}catch(b){c.localStorage.error(b)}return q},parse:function(a){try{return c.P(c.localStorage.get(a))||{}}catch(b){}return q},set:function(a,b){try{window.localStorage.setItem(a,b)}catch(d){c.localStorage.error(d)}},remove:function(a){try{window.localStorage.removeItem(a)}catch(b){c.localStorage.error(b)}}}; +c.Pb=function(){function a(a,f,h){return function(g){if(g=g||b(window.event)){var e=m,i;c.Ra(h)&&(i=h(g));g=f.call(a,g);if(D===i||D===g)e=D;return e}}}function b(a){if(a)a.preventDefault=b.preventDefault,a.stopPropagation=b.stopPropagation;return a}b.preventDefault=function(){this.returnValue=D};b.stopPropagation=function(){this.cancelBubble=m};return function(b,c,h,g,e){b?b.addEventListener&&!g?b.addEventListener(c,h,!!e):(c="on"+c,b[c]=a(b,h,b[c])):o.error("No valid element provided to register_event")}}(); +var Na=/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/;c.yc=function(){function a(a,b){return 0<=(" "+a.className+" ").replace(d," ").indexOf(" "+b+" ")}function b(b){if(!u.getElementsByTagName)return[];var b=b.split(" "),d,g,e,i,k,r,p,x=[u];for(i=0;iv?(Qa.error("Timeout waiting for mutex on "+p+"; clearing lock. ["+k+"]"),j.removeItem(u),j.removeItem(o),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},x*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=q);var k=c||(new Date).getTime()+"|"+Math.random(),r=(new Date).getTime(), +p=this.L,x=this.Nb,v=this.$b,j=this.i,n=p+":X",o=p+":Y",u=p+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(t){b&&b(t)}};var pa=ga("batch");G.prototype.Ka=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.Ua.cb(c.bind(function(){var b;try{var c=this.Z();c.push(f);(b=this.Xa(c))&&this.G.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock",a);d&&d(D)},this), +this.qa)};G.prototype.Ac=function(a){var b=this.G.slice(0,a);if(b.lengthg.flushAfter&&!f[g.id]&&(g.Nc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Pc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.G=oa(this.G,d);var f=c.bind(function(){var b;try{var c=this.Z(),c=oa(c,d);if(b=this.Xa(c))for(var c=this.Z(),f=0;fe.length)this.$();else{this.Rb=m;var i=c.bind(function(e){this.Rb= +D;try{var g=D;if(a.ec)this.X.qd(s);else if(c.e(e)&&"timeout"===e.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(e)&&e.O&&(500<=e.O.status||429===e.O.status||"timeout"===e.error)){var i=2*this.ma,k=e.O.responseHeaders;if(k){var j=k["Retry-After"];j&&(i=1E3*parseInt(j,10)||i)}i=Math.min(6E5,i);this.h("Error; retry in "+i+" ms");this.Tb(i)}else if(c.e(e)&&e.O&&413===e.O.status)if(1=v.timeout? +"timeout":"Bad HTTP status: "+v.status+" "+v.statusText,n.l(a),e&&(k?e({status:0,error:a,O:v}):e(0))};v.send(j)}catch(y){n.l(y),h=D}else j=u.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,t=u.getElementsByTagName("script")[0],t.parentNode.insertBefore(j,t);return h};e.prototype.xa=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a, +function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this):c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.nb=function(){return!!this.u.J};e.prototype.yb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.fb=this.fb||{J:{type:"events",D:"/"+b.track,Y:a+"_ev"},Wa:{type:"people",D:"/"+b.engage,Y:a+"_pp"},Oa:{type:"groups",D:"/"+ +b.groups,Y:a+"_gr"}}};e.prototype.Gc=function(){if(!this.nb()){var a=c.bind(function(a){return new C(a.Y,{A:this.config,Wc:c.bind(function(b,c,e){this.k(this.c("api_host")+a.D,this.hb(b),c,this.jb(e,b))},this),ha:c.bind(function(b){return this.lb("before_send_"+a.type,b)},this),I:this.c("error_reporter"),fd:c.bind(this.Za,this)})},this),b=this.yb();this.u={J:a(b.J),Wa:a(b.Wa),Oa:a(b.Oa)}}this.c("batch_autostart")&&this.Ya()};e.prototype.Ya=function(){this.kc=m;if(this.nb())this.Q=m,c.a(this.u,function(a){a.start()})}; +e.prototype.Za=function(){this.Q=D;c.a(this.u,function(a){a.stop();a.clear()})};e.prototype.push=function(a){this.xa([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.R.xc=m:this.ua=this.ua.concat(a)};e.prototype.hb=function(a){a=c.da(a);"base64"===this.c("api_payload_format")&&(a=c.uc(a));return{data:a}};e.prototype.Da=function(a,b){var d=c.truncate(a.data,255),e=a.D,h=a.Fa,g=a.dd,j=a.Xc||{},b=b||P,i=m,k=c.bind(function(){j.Zb||(d=this.lb("before_send_"+a.type,d));return d?(o.log("MIXPANEL REQUEST:"), +o.log(d),this.k(e,this.hb(d),j,this.jb(b,d))):q},this);this.Q&&!g?h.Ka(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=M(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=q);var d=d||{},h=d.transport;if(h)d.ab=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.g(a))this.l("No event name provided to mixpanel.track");else if(this.ib(a))e(0);else{b=c.extend({},b);b.token=this.c("token");var g=this.persistence.Qc(a);c.g(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3))); +this.mb();g=this.c("track_marketing")?c.info.Kc():{};b=c.extend({},c.info.W(),g,this.persistence.W(),this.N,b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Da({type:"events",data:{event:a,properties:b},D:this.c("api_host")+"/"+this.c("api_routes").track,Fa:this.u.J,dd:h,Xc:d},e)}});e.prototype.bd=M(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.rc= +M(function(a,b,c){var e=this.s(a);if(e===l){var h={};h[a]=[b];this.m(h)}else-1===e.indexOf(b)&&(e.push(b),this.m(h));return this.people.ba(a,b,c)});e.prototype.Rc=M(function(a,b,c){var e=this.s(a);if(e!==l){var h=e.indexOf(b);-1(y.__SV||0)?o.H("Version mismatch; please ensure you're using the latest version of the Mixpanel code snippet."):(c.a(y._i,function(a){a&&c.isArray(a)&&(F[a[a.length-1]]=S.apply(this,a))}),Ba(),y.init(),c.a(F,function(a){a.ga()}),Aa())})()})(); })(); diff --git a/dist/mixpanel.umd.js b/dist/mixpanel.umd.js index 4a4c8f62..44ad99da 100644 --- a/dist/mixpanel.umd.js +++ b/dist/mixpanel.umd.js @@ -6,7 +6,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -908,6 +908,7 @@ 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', @@ -3136,7 +3137,7 @@ return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3497,7 +3498,7 @@ return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3533,11 +3534,12 @@ MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3559,8 +3561,6 @@ _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3570,6 +3570,7 @@ // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -3591,6 +3592,7 @@ } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { @@ -3689,6 +3691,9 @@ MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -3765,6 +3770,7 @@ MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -3776,6 +3782,17 @@ ); }; + MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; + }; + + MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; + }; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3799,6 +3816,8 @@ if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3820,8 +3839,8 @@ if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -3830,6 +3849,7 @@ }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3856,19 +3876,6 @@ }); }; - // safely fills the passed in object with stored properties, - // does not override any properties defined in both - // returns the passed in object - MixpanelPersistence.prototype.safe_merge = function(props) { - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; - }; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -4012,7 +4019,7 @@ }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -4028,11 +4035,13 @@ delete q[k]; } }, this); - - this.save(); } }; + MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); + }; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -4053,25 +4062,20 @@ } }; - MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; - }; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4142,11 +4146,18 @@ }; } + var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' + }; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -4345,6 +4356,10 @@ if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window$1.addEventListener) { @@ -4692,12 +4707,22 @@ return !!this.request_batchers.events; }; + MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; + }; + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -4716,10 +4741,11 @@ } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -4728,6 +4754,7 @@ }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -4879,7 +4906,7 @@ } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -4925,7 +4952,7 @@ var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -5522,6 +5549,16 @@ * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -5778,9 +5815,13 @@ } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -5982,37 +6023,38 @@ // EXPORTS (for closure compiler) // MixpanelLib Exports - MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; - MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; - MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; - MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; - MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; - MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; - MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; - MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; - MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; - MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; - MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; - MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; - MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; - MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; - MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; - MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; - MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; - MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; - MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; - MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; - MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; - MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; - MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; - MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; - MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; - MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; - MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; - MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; - MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; - MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; - MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; + MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; + MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; + MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; + MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; + MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; + MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; + MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; + MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; + MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; + MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; + MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; + MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; + MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; + MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; + MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; + MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; + MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; + MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; + MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; + MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; + MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; + MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; + MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; + MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; + MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; + MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; + MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; + MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; + MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; + MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; diff --git a/examples/commonjs-browserify/bundle.js b/examples/commonjs-browserify/bundle.js index 6f7e2c78..e12dacac 100644 --- a/examples/commonjs-browserify/bundle.js +++ b/examples/commonjs-browserify/bundle.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -905,6 +905,7 @@ var BLOCKED_UA_STRS = [ 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', @@ -3133,7 +3134,7 @@ MixpanelGroup.prototype._send_request = function(data, callback) { return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3494,7 +3495,7 @@ MixpanelPeople.prototype._send_request = function(data, callback) { return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3530,11 +3531,12 @@ MixpanelPeople.prototype._enqueue = function(data) { MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3556,8 +3558,6 @@ MixpanelPeople.prototype._flush = function( _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3567,6 +3567,7 @@ MixpanelPeople.prototype._flush = function( // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -3588,6 +3589,7 @@ MixpanelPeople.prototype._flush = function( } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { @@ -3686,6 +3688,9 @@ var MixpanelPersistence = function(config) { MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -3762,6 +3767,7 @@ MixpanelPersistence.prototype.upgrade = function(config) { MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -3773,6 +3779,17 @@ MixpanelPersistence.prototype.save = function() { ); }; +MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; +}; + +MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; +}; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3796,6 +3813,8 @@ MixpanelPersistence.prototype.register_once = function(props, default_value, day if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3817,8 +3836,8 @@ MixpanelPersistence.prototype.register = function(props, days) { if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -3827,6 +3846,7 @@ MixpanelPersistence.prototype.register = function(props, days) { }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3853,19 +3873,6 @@ MixpanelPersistence.prototype.get_referrer_info = function() { }); }; -// safely fills the passed in object with stored properties, -// does not override any properties defined in both -// returns the passed in object -MixpanelPersistence.prototype.safe_merge = function(props) { - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; -}; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -4009,7 +4016,7 @@ MixpanelPersistence.prototype._add_to_people_queue = function(queue, data) { }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -4025,11 +4032,13 @@ MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { delete q[k]; } }, this); - - this.save(); } }; +MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); +}; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -4050,25 +4059,20 @@ MixpanelPersistence.prototype._get_queue_key = function(queue) { } }; -MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; -}; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4139,11 +4143,18 @@ if (navigator['sendBeacon']) { }; } +var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' +}; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -4342,6 +4353,10 @@ MixpanelLib.prototype._init = function(token, config, name) { if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window$1.addEventListener) { @@ -4689,12 +4704,22 @@ MixpanelLib.prototype.are_batchers_initialized = function() { return !!this.request_batchers.events; }; +MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; +}; + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -4713,10 +4738,11 @@ MixpanelLib.prototype.init_batchers = function() { } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -4725,6 +4751,7 @@ MixpanelLib.prototype.init_batchers = function() { }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -4876,7 +4903,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -4922,7 +4949,7 @@ MixpanelLib.prototype.track = addOptOutCheckMixpanelLib(function(event_name, pro var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -5519,6 +5546,16 @@ MixpanelLib.prototype.name_tag = function(name_tag) { * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -5775,9 +5812,13 @@ MixpanelLib.prototype._gdpr_update_persistence = function(options) { } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -5979,37 +6020,38 @@ MixpanelLib.prototype.report_error = function(msg, err) { // EXPORTS (for closure compiler) // MixpanelLib Exports -MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; -MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; -MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; -MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; -MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; -MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; -MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; -MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; -MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; -MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; -MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; -MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; -MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; -MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; -MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; -MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; -MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; -MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; -MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; -MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; -MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; -MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; -MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; -MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; -MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; -MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; -MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; -MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; -MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; -MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; -MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; +MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; +MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; +MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; +MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; +MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; +MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; +MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; +MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; +MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; +MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; +MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; +MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; +MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; +MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; +MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; +MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; +MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; +MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; +MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; +MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; +MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; +MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; +MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; +MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; +MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; +MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; +MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; +MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; +MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; +MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; diff --git a/examples/es2015-babelify/bundle.js b/examples/es2015-babelify/bundle.js index e0c86ba4..753aee1b 100644 --- a/examples/es2015-babelify/bundle.js +++ b/examples/es2015-babelify/bundle.js @@ -163,7 +163,7 @@ Object.defineProperty(exports, '__esModule', { }); var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; exports['default'] = Config; @@ -753,11 +753,18 @@ if (_utils.navigator['sendBeacon']) { }; } +var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' +}; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -955,6 +962,10 @@ MixpanelLib.prototype._init = function (token, config, name) { if (!_utils._.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; _utils.console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _utils._.each(this.get_batcher_configs(), function (batcher_config) { + _utils.console.log('Clearing batch queue ' + batcher_config.queue_key); + _utils._.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && _utils.window.addEventListener) { @@ -1310,11 +1321,21 @@ MixpanelLib.prototype.are_batchers_initialized = function () { return !!this.request_batchers.events; }; +MixpanelLib.prototype.get_batcher_configs = function () { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: { type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev' }, + people: { type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp' }, + groups: { type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr' } + }; + return this._batcher_configs; +}; + MixpanelLib.prototype.init_batchers = function () { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _utils._.bind(function (attrs) { - return new _requestBatcher.RequestBatcher('__mpq_' + token + attrs.queue_suffix, { + return new _requestBatcher.RequestBatcher(attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _utils._.bind(function (data, options, cb) { this._send_request(this.get_config('api_host') + attrs.endpoint, this._encode_data_for_request(data), options, this._prepare_callback(cb, data)); @@ -1326,10 +1347,11 @@ MixpanelLib.prototype.init_batchers = function () { stopAllBatchingFunc: _utils._.bind(this.stop_batch_senders, this) }); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({ type: 'events', endpoint: '/track/', queue_suffix: '_ev' }), - people: batcher_for({ type: 'people', endpoint: '/engage/', queue_suffix: '_pp' }), - groups: batcher_for({ type: 'groups', endpoint: '/groups/', queue_suffix: '_gr' }) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -1338,6 +1360,7 @@ MixpanelLib.prototype.init_batchers = function () { }; MixpanelLib.prototype.start_batch_senders = function () { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _utils._.each(this.request_batchers, function (batcher) { @@ -1484,7 +1507,7 @@ MixpanelLib.prototype.track = (0, _gdprUtils.addOptOutCheckMixpanelLib)(function } // set defaults - properties = properties || {}; + properties = _utils._.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -1521,7 +1544,7 @@ MixpanelLib.prototype.track = (0, _gdprUtils.addOptOutCheckMixpanelLib)(function var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -2108,6 +2131,16 @@ MixpanelLib.prototype.name_tag = function (name_tag) { * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -2360,9 +2393,13 @@ MixpanelLib.prototype._gdpr_update_persistence = function (options) { } if (disabled) { - _utils._.each(this.request_batchers, function (batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -2595,6 +2632,7 @@ MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; +MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports _mixpanelPersistence.MixpanelPersistence.prototype['properties'] = _mixpanelPersistence.MixpanelPersistence.prototype.properties; @@ -2916,7 +2954,7 @@ MixpanelGroup.prototype._send_request = function (data, callback) { return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3288,7 +3326,7 @@ MixpanelPeople.prototype._send_request = function (data, callback) { return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3324,11 +3362,12 @@ MixpanelPeople.prototype._enqueue = function (data) { MixpanelPeople.prototype._flush_one_queue = function (action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _utils._.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _utils._.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_utils._.isUndefined(queued_data) && _utils._.isObject(queued_data) && !_utils._.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3348,8 +3387,6 @@ MixpanelPeople.prototype._flush_one_queue = function (action, action_method, cal // and there are network level race conditions anyway MixpanelPeople.prototype._flush = function (_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(_apiActions.APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(_apiActions.REMOVE_ACTION); this._flush_one_queue(_apiActions.SET_ACTION, this.set, _set_callback); this._flush_one_queue(_apiActions.SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3361,6 +3398,7 @@ MixpanelPeople.prototype._flush = function (_set_callback, _add_callback, _appen // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(_apiActions.APPEND_ACTION); if (!_utils._.isUndefined($append_queue) && _utils._.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function append_callback(response, data) { @@ -3382,6 +3420,7 @@ MixpanelPeople.prototype._flush = function (_set_callback, _add_callback, _appen } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(_apiActions.REMOVE_ACTION); if (!_utils._.isUndefined($remove_queue) && _utils._.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function remove_callback(response, data) { @@ -3484,6 +3523,9 @@ var MixpanelPersistence = function MixpanelPersistence(config) { MixpanelPersistence.prototype.properties = function () { var p = {}; + + this.load(); + // Filter out reserved properties _utils._.each(this['props'], function (v, k) { if (!_utils._.include(RESERVED_PROPERTIES, k)) { @@ -3560,9 +3602,21 @@ MixpanelPersistence.prototype.save = function () { if (this.disabled) { return; } + this.storage.set(this.name, _utils._.JSONEncode(this['props']), this.expire_days, this.cross_subdomain, this.secure, this.cross_site, this.cookie_domain); }; +MixpanelPersistence.prototype._load_prop = function (key) { + this.load(); + return this['props'][key]; +}; + +MixpanelPersistence.prototype._save_prop = function (key, val) { + this['props'][key] = val; + this.save(); + return val; +}; + MixpanelPersistence.prototype.remove = function () { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3588,6 +3642,8 @@ MixpanelPersistence.prototype.register_once = function (props, default_value, da } this.expire_days = typeof days === 'undefined' ? this.default_expiry : days; + this.load(); + _utils._.each(props, function (val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3609,8 +3665,8 @@ MixpanelPersistence.prototype.register = function (props, days) { if (_utils._.isObject(props)) { this.expire_days = typeof days === 'undefined' ? this.default_expiry : days; + this.load(); _utils._.extend(this['props'], props); - this.save(); return true; @@ -3619,6 +3675,7 @@ MixpanelPersistence.prototype.register = function (props, days) { }; MixpanelPersistence.prototype.unregister = function (prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3645,19 +3702,6 @@ MixpanelPersistence.prototype.get_referrer_info = function () { }); }; -// safely fills the passed in object with stored properties, -// does not override any properties defined in both -// returns the passed in object -MixpanelPersistence.prototype.safe_merge = function (props) { - _utils._.each(this['props'], function (val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; -}; - MixpanelPersistence.prototype.update_config = function (config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -3800,7 +3844,7 @@ MixpanelPersistence.prototype._add_to_people_queue = function (queue, data) { }; MixpanelPersistence.prototype._pop_from_people_queue = function (queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_utils._.isUndefined(q)) { _utils._.each(data, function (v, k) { if (queue === _apiActions.APPEND_ACTION || queue === _apiActions.REMOVE_ACTION) { @@ -3816,11 +3860,13 @@ MixpanelPersistence.prototype._pop_from_people_queue = function (queue, data) { delete q[k]; } }, this); - - this.save(); } }; +MixpanelPersistence.prototype.load_queue = function (queue) { + return this._load_prop(this._get_queue_key(queue)); +}; + MixpanelPersistence.prototype._get_queue_key = function (queue) { if (queue === _apiActions.SET_ACTION) { return SET_QUEUE_KEY; @@ -3841,25 +3887,20 @@ MixpanelPersistence.prototype._get_queue_key = function (queue) { } }; -MixpanelPersistence.prototype._get_queue = function (queue) { - return this['props'][this._get_queue_key(queue)]; -}; MixpanelPersistence.prototype._get_or_create_queue = function (queue, default_val) { var key = this._get_queue_key(queue); default_val = _utils._.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function (event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function (event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_utils._.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -5546,7 +5587,7 @@ _.UUID = (function () { // _.isBlockedUA() // This is to block various web spiders from executing our JS and // sending false tracking data -var BLOCKED_UA_STRS = ['ahrefsbot', 'baiduspider', 'bingbot', 'bingpreview', 'facebookexternal', 'petalbot', 'pinterest', 'screaming frog', 'yahoo! slurp', 'yandexbot', +var BLOCKED_UA_STRS = ['ahrefsbot', 'baiduspider', 'bingbot', 'bingpreview', 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', 'screaming frog', 'yahoo! slurp', 'yandexbot', // a whole bunch of goog-specific crawlers // https://developers.google.com/search/docs/advanced/crawling/overview-google-crawlers diff --git a/examples/umd-webpack/bundle.js b/examples/umd-webpack/bundle.js index 3fcdc05b..d542c3ac 100644 --- a/examples/umd-webpack/bundle.js +++ b/examples/umd-webpack/bundle.js @@ -69,7 +69,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -971,6 +971,7 @@ 'baiduspider', 'bingbot', 'bingpreview', + 'chrome-lighthouse', 'facebookexternal', 'petalbot', 'pinterest', @@ -3199,7 +3200,7 @@ return this._mixpanel._track_or_batch({ type: 'groups', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/groups/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['groups'], batcher: this._mixpanel.request_batchers.groups }, callback); }; @@ -3560,7 +3561,7 @@ return this._mixpanel._track_or_batch({ type: 'people', data: date_encoded_data, - endpoint: this._get_config('api_host') + '/engage/', + endpoint: this._get_config('api_host') + '/' + this._get_config('api_routes')['engage'], batcher: this._mixpanel.request_batchers.people }, callback); }; @@ -3596,11 +3597,12 @@ MixpanelPeople.prototype._flush_one_queue = function(action, action_method, callback, queue_to_params_fn) { var _this = this; - var queued_data = _.extend({}, this._mixpanel['persistence']._get_queue(action)); + var queued_data = _.extend({}, this._mixpanel['persistence'].load_queue(action)); var action_params = queued_data; if (!_.isUndefined(queued_data) && _.isObject(queued_data) && !_.isEmptyObject(queued_data)) { _this._mixpanel['persistence']._pop_from_people_queue(action, queued_data); + _this._mixpanel['persistence'].save(); if (queue_to_params_fn) { action_params = queue_to_params_fn(queued_data); } @@ -3622,8 +3624,6 @@ _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback ) { var _this = this; - var $append_queue = this._mixpanel['persistence']._get_queue(APPEND_ACTION); - var $remove_queue = this._mixpanel['persistence']._get_queue(REMOVE_ACTION); this._flush_one_queue(SET_ACTION, this.set, _set_callback); this._flush_one_queue(SET_ONCE_ACTION, this.set_once, _set_once_callback); @@ -3633,6 +3633,7 @@ // we have to fire off each $append individually since there is // no concat method server side + var $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); if (!_.isUndefined($append_queue) && _.isArray($append_queue) && $append_queue.length) { var $append_item; var append_callback = function(response, data) { @@ -3654,6 +3655,7 @@ } // same for $remove + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); if (!_.isUndefined($remove_queue) && _.isArray($remove_queue) && $remove_queue.length) { var $remove_item; var remove_callback = function(response, data) { @@ -3752,6 +3754,9 @@ MixpanelPersistence.prototype.properties = function() { var p = {}; + + this.load(); + // Filter out reserved properties _.each(this['props'], function(v, k) { if (!_.include(RESERVED_PROPERTIES, k)) { @@ -3828,6 +3833,7 @@ MixpanelPersistence.prototype.save = function() { if (this.disabled) { return; } + this.storage.set( this.name, _.JSONEncode(this['props']), @@ -3839,6 +3845,17 @@ ); }; + MixpanelPersistence.prototype._load_prop = function(key) { + this.load(); + return this['props'][key]; + }; + + MixpanelPersistence.prototype._save_prop = function(key, val) { + this['props'][key] = val; + this.save(); + return val; + }; + MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3862,6 +3879,8 @@ if (typeof(default_value) === 'undefined') { default_value = 'None'; } this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); + _.each(props, function(val, prop) { if (!this['props'].hasOwnProperty(prop) || this['props'][prop] === default_value) { this['props'][prop] = val; @@ -3883,8 +3902,8 @@ if (_.isObject(props)) { this.expire_days = (typeof(days) === 'undefined') ? this.default_expiry : days; + this.load(); _.extend(this['props'], props); - this.save(); return true; @@ -3893,6 +3912,7 @@ }; MixpanelPersistence.prototype.unregister = function(prop) { + this.load(); if (prop in this['props']) { delete this['props'][prop]; this.save(); @@ -3919,19 +3939,6 @@ }); }; - // safely fills the passed in object with stored properties, - // does not override any properties defined in both - // returns the passed in object - MixpanelPersistence.prototype.safe_merge = function(props) { - _.each(this['props'], function(val, prop) { - if (!(prop in props)) { - props[prop] = val; - } - }); - - return props; - }; - MixpanelPersistence.prototype.update_config = function(config) { this.default_expiry = this.expire_days = config['cookie_expiration']; this.set_disabled(config['disable_persistence']); @@ -4075,7 +4082,7 @@ }; MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { - var q = this._get_queue(queue); + var q = this['props'][this._get_queue_key(queue)]; if (!_.isUndefined(q)) { _.each(data, function(v, k) { if (queue === APPEND_ACTION || queue === REMOVE_ACTION) { @@ -4091,11 +4098,13 @@ delete q[k]; } }, this); - - this.save(); } }; + MixpanelPersistence.prototype.load_queue = function(queue) { + return this._load_prop(this._get_queue_key(queue)); + }; + MixpanelPersistence.prototype._get_queue_key = function(queue) { if (queue === SET_ACTION) { return SET_QUEUE_KEY; @@ -4116,25 +4125,20 @@ } }; - MixpanelPersistence.prototype._get_queue = function(queue) { - return this['props'][this._get_queue_key(queue)]; - }; MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val) { var key = this._get_queue_key(queue); default_val = _.isUndefined(default_val) ? {} : default_val; - return this['props'][key] || (this['props'][key] = default_val); }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this['props'][EVENT_TIMERS_KEY] = timers; - this.save(); + this._save_prop(EVENT_TIMERS_KEY, timers); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this['props'][EVENT_TIMERS_KEY] || {}; + var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4205,11 +4209,18 @@ }; } + var DEFAULT_API_ROUTES = { + 'track': 'track/', + 'engage': 'engage/', + 'groups': 'groups/' + }; + /* * Module-level globals */ var DEFAULT_CONFIG = { 'api_host': 'https://api-js.mixpanel.com', + 'api_routes': DEFAULT_API_ROUTES, 'api_method': 'POST', 'api_transport': 'XHR', 'api_payload_format': PAYLOAD_TYPE_BASE64, @@ -4408,6 +4419,10 @@ if (!_.localStorage.is_supported(true) || !USE_XHR) { this._batch_requests = false; console.log('Turning off Mixpanel request-queueing; needs XHR and localStorage support'); + _.each(this.get_batcher_configs(), function(batcher_config) { + console.log('Clearing batch queue ' + batcher_config.queue_key); + _.localStorage.remove(batcher_config.queue_key); + }); } else { this.init_batchers(); if (sendBeacon && window$1.addEventListener) { @@ -4755,12 +4770,22 @@ return !!this.request_batchers.events; }; + MixpanelLib.prototype.get_batcher_configs = function() { + var queue_prefix = '__mpq_' + this.get_config('token'); + var api_routes = this.get_config('api_routes'); + this._batcher_configs = this._batcher_configs || { + events: {type: 'events', endpoint: '/' + api_routes['track'], queue_key: queue_prefix + '_ev'}, + people: {type: 'people', endpoint: '/' + api_routes['engage'], queue_key: queue_prefix + '_pp'}, + groups: {type: 'groups', endpoint: '/' + api_routes['groups'], queue_key: queue_prefix + '_gr'} + }; + return this._batcher_configs; + }; + MixpanelLib.prototype.init_batchers = function() { - var token = this.get_config('token'); if (!this.are_batchers_initialized()) { var batcher_for = _.bind(function(attrs) { return new RequestBatcher( - '__mpq_' + token + attrs.queue_suffix, + attrs.queue_key, { libConfig: this['config'], sendRequestFunc: _.bind(function(data, options, cb) { @@ -4779,10 +4804,11 @@ } ); }, this); + var batcher_configs = this.get_batcher_configs(); this.request_batchers = { - events: batcher_for({type: 'events', endpoint: '/track/', queue_suffix: '_ev'}), - people: batcher_for({type: 'people', endpoint: '/engage/', queue_suffix: '_pp'}), - groups: batcher_for({type: 'groups', endpoint: '/groups/', queue_suffix: '_gr'}) + events: batcher_for(batcher_configs.events), + people: batcher_for(batcher_configs.people), + groups: batcher_for(batcher_configs.groups) }; } if (this.get_config('batch_autostart')) { @@ -4791,6 +4817,7 @@ }; MixpanelLib.prototype.start_batch_senders = function() { + this._batchers_were_started = true; if (this.are_batchers_initialized()) { this._batch_requests = true; _.each(this.request_batchers, function(batcher) { @@ -4942,7 +4969,7 @@ } // set defaults - properties = properties || {}; + properties = _.extend({}, properties); properties['token'] = this.get_config('token'); // set $duration if time_event was previously called for this event @@ -4988,7 +5015,7 @@ var ret = this._track_or_batch({ type: 'events', data: data, - endpoint: this.get_config('api_host') + '/track/', + endpoint: this.get_config('api_host') + '/' + this.get_config('api_routes')['track'], batcher: this.request_batchers.events, should_send_immediately: should_send_immediately, send_request_options: options @@ -5585,6 +5612,16 @@ * The default config is: * * { + * // host for requests (customizable for e.g. a local proxy) + * api_host: 'https://api-js.mixpanel.com', + * + * // endpoints for different types of requests + * api_routes: { + * track: 'track/', + * engage: 'engage/', + * groups: 'groups/', + * } + * * // HTTP method for tracking requests * api_method: 'POST' * @@ -5841,9 +5878,13 @@ } if (disabled) { - _.each(this.request_batchers, function(batcher) { - batcher.clear(); - }); + this.stop_batch_senders(); + } else { + // only start batchers after opt-in if they have previously been started + // in order to avoid unintentionally starting up batching for the first time + if (this._batchers_were_started) { + this.start_batch_senders(); + } } }; @@ -6045,37 +6086,38 @@ // EXPORTS (for closure compiler) // MixpanelLib Exports - MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; - MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; - MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; - MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; - MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; - MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; - MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; - MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; - MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; - MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; - MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; - MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; - MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; - MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; - MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; - MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; - MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; - MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; - MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; - MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; - MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; - MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; - MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; - MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; - MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; - MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; - MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; - MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; - MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; - MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; - MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['init'] = MixpanelLib.prototype.init; + MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset; + MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable; + MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event; + MixpanelLib.prototype['track'] = MixpanelLib.prototype.track; + MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links; + MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms; + MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview; + MixpanelLib.prototype['register'] = MixpanelLib.prototype.register; + MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once; + MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister; + MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify; + MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias; + MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag; + MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config; + MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config; + MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property; + MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id; + MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString; + MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking; + MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking; + MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking; + MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking; + MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking; + MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group; + MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group; + MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group; + MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group; + MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups; + MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders; + MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders; + MixpanelLib.prototype['DEFAULT_API_ROUTES'] = DEFAULT_API_ROUTES; // MixpanelPersistence Exports MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties; diff --git a/src/config.js b/src/config.js index 32b26d2d..bea9a66f 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,6 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.47.0' + LIB_VERSION: '2.48.0-rc1' }; export default Config; From e539fd158d1502f3bab77a0f682f0024ad9e57f1 Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 27 Sep 2023 22:39:05 +0000 Subject: [PATCH 14/26] _save_prop is unnecessary now --- src/mixpanel-persistence.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/mixpanel-persistence.js b/src/mixpanel-persistence.js index 7e7dc3f7..bbe63916 100644 --- a/src/mixpanel-persistence.js +++ b/src/mixpanel-persistence.js @@ -163,17 +163,11 @@ MixpanelPersistence.prototype.save = function() { ); }; -MixpanelPersistence.prototype._load_prop = function(key) { +MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; -MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; -}; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -420,7 +414,7 @@ MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -450,13 +444,14 @@ MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; From 088a0d203a052211f39a56d2eb1466bfd1a92c7f Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 27 Sep 2023 23:30:11 +0000 Subject: [PATCH 15/26] make load_property read from persisted data --- src/mixpanel-core.js | 2 +- src/mixpanel-people.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index e712f7e8..dd0c5548 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -1677,7 +1677,7 @@ MixpanelLib.prototype._run_hook = function(hook_name) { * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/src/mixpanel-people.js b/src/mixpanel-people.js index a94e5507..b90da291 100644 --- a/src/mixpanel-people.js +++ b/src/mixpanel-people.js @@ -432,13 +432,13 @@ MixpanelPeople.prototype._flush = function( } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -454,12 +454,13 @@ MixpanelPeople.prototype._flush = function( } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; From 87d2dc7b24f6ace5fd1393e5899689570ff5fb59 Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 27 Sep 2023 23:32:49 +0000 Subject: [PATCH 16/26] fix persistence bug in add_group --- src/mixpanel-core.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index dd0c5548..f546e84d 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -933,13 +933,14 @@ MixpanelLib.prototype.set_group = addOptOutCheckMixpanelLib(function(group_key, */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } From a816099e679bf73e8090c047c2e771b79bacb4f5 Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 27 Sep 2023 23:34:24 +0000 Subject: [PATCH 17/26] extraneous var decl --- src/mixpanel-people.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixpanel-people.js b/src/mixpanel-people.js index b90da291..43d3ddad 100644 --- a/src/mixpanel-people.js +++ b/src/mixpanel-people.js @@ -454,7 +454,7 @@ MixpanelPeople.prototype._flush = function( } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { - var $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { From a4baa20d20e5c73aa34db3224bf00fc777a5d2ec Mon Sep 17 00:00:00 2001 From: teddddd Date: Wed, 27 Sep 2023 23:36:22 +0000 Subject: [PATCH 18/26] v2.48.0-rc2 --- dist/mixpanel.amd.js | 31 ++--- dist/mixpanel.cjs.js | 31 ++--- dist/mixpanel.globals.js | 31 ++--- dist/mixpanel.min.js | 184 ++++++++++++------------- dist/mixpanel.umd.js | 31 ++--- examples/commonjs-browserify/bundle.js | 31 ++--- examples/es2015-babelify/bundle.js | 31 ++--- examples/umd-webpack/bundle.js | 31 ++--- src/config.js | 2 +- 9 files changed, 191 insertions(+), 212 deletions(-) diff --git a/dist/mixpanel.amd.js b/dist/mixpanel.amd.js index 7e9ed517..5d8c5672 100644 --- a/dist/mixpanel.amd.js +++ b/dist/mixpanel.amd.js @@ -2,7 +2,7 @@ define(function () { 'use strict'; var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -3578,13 +3578,13 @@ define(function () { 'use strict'; } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3600,12 +3600,13 @@ define(function () { 'use strict'; } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3778,17 +3779,11 @@ define(function () { 'use strict'; ); }; - MixpanelPersistence.prototype._load_prop = function(key) { + MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; - MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; - }; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -4035,7 +4030,7 @@ define(function () { 'use strict'; }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -4065,13 +4060,14 @@ define(function () { 'use strict'; }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4994,13 +4990,14 @@ define(function () { 'use strict'; */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -5738,7 +5735,7 @@ define(function () { 'use strict'; * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/dist/mixpanel.cjs.js b/dist/mixpanel.cjs.js index 8595ed50..623689ad 100644 --- a/dist/mixpanel.cjs.js +++ b/dist/mixpanel.cjs.js @@ -2,7 +2,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -3578,13 +3578,13 @@ MixpanelPeople.prototype._flush = function( } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3600,12 +3600,13 @@ MixpanelPeople.prototype._flush = function( } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3778,17 +3779,11 @@ MixpanelPersistence.prototype.save = function() { ); }; -MixpanelPersistence.prototype._load_prop = function(key) { +MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; -MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; -}; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -4035,7 +4030,7 @@ MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -4065,13 +4060,14 @@ MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4994,13 +4990,14 @@ MixpanelLib.prototype.set_group = addOptOutCheckMixpanelLib(function(group_key, */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -5738,7 +5735,7 @@ MixpanelLib.prototype._run_hook = function(hook_name) { * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/dist/mixpanel.globals.js b/dist/mixpanel.globals.js index 0782310a..a1114206 100644 --- a/dist/mixpanel.globals.js +++ b/dist/mixpanel.globals.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -3579,13 +3579,13 @@ } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3601,12 +3601,13 @@ } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3779,17 +3780,11 @@ ); }; - MixpanelPersistence.prototype._load_prop = function(key) { + MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; - MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; - }; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -4036,7 +4031,7 @@ }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -4066,13 +4061,14 @@ }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4995,13 +4991,14 @@ */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -5739,7 +5736,7 @@ * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/dist/mixpanel.min.js b/dist/mixpanel.min.js index 3a3378ad..f3228121 100644 --- a/dist/mixpanel.min.js +++ b/dist/mixpanel.min.js @@ -1,107 +1,107 @@ (function() { var l=void 0,m=!0,q=null,D=!1; -(function(){function Aa(){function a(){if(!a.zc)la=a.zc=m,ma=D,c.a(F,function(a){a.mc()})}function b(){try{u.documentElement.doScroll("left")}catch(d){setTimeout(b,1);return}a()}if(u.addEventListener)"complete"===u.readyState?a():u.addEventListener("DOMContentLoaded",a,D);else if(u.attachEvent){u.attachEvent("onreadystatechange",a);var d=D;try{d=w.frameElement===q}catch(f){}u.documentElement.doScroll&&d&&b()}c.Pb(w,"load",a,m)}function Ba(){y.init=function(a,b,d){if(d)return y[d]||(y[d]=F[d]=S(a, -b,d),y[d].ga()),y[d];d=y;if(F.mixpanel)d=F.mixpanel;else if(a)d=S(a,b,"mixpanel"),d.ga(),F.mixpanel=d;y=d;1===ca&&(w.mixpanel=y);Ca()}}function Ca(){c.a(F,function(a,b){"mixpanel"!==b&&(y[b]=a)});y._=c}function da(a){a=c.e(a)?a:c.g(a)?{}:{days:a};return c.extend({},Da,a)}function S(a,b,d){var f,h="mixpanel"===d?y:y[d];if(h&&0===ca)f=h;else{if(h&&!c.isArray(h)){o.error("You have already initialized "+d);return}f=new e}f.gb={};f.U(a,b,d);f.people=new j;f.people.U(f);if(!f.c("skip_first_touch_marketing")){var a= -c.info.ja(q),g={},s=D;c.a(a,function(a,b){(g["initial_"+b]=a)&&(s=m)});s&&f.people.aa(g)}J=J||f.c("debug");!c.g(h)&&c.isArray(h)&&(f.xa.call(f.people,h.people),f.xa(h));return f}function e(){}function P(){}function Ea(a){return a}function n(a){this.props={};this.vd=D;this.name=a.persistence_name?"mp_"+a.persistence_name:"mp_"+a.token+"_mixpanel";var b=a.persistence;if("cookie"!==b&&"localStorage"!==b)o.H("Unknown persistence type "+b+"; falling back to cookie"),b=a.persistence="cookie";this.i="localStorage"=== -b&&c.localStorage.pa()?c.localStorage:c.cookie;this.load();this.gc(a);this.rd(a);this.save()}function j(){}function t(){}function C(a,b){this.I=b.I;this.X=new G(a,{I:c.bind(this.h,this),i:b.i});this.A=b.A;this.Vc=b.Wc;this.ha=b.ha;this.ed=b.fd;this.C=this.A.batch_size;this.ma=this.A.batch_flush_interval_ms;this.ra=!this.A.batch_autostart;this.Ha=0;this.F={}}function na(a,b){var d=[];c.a(a,function(a){var c=a.id;if(c in b){if(c=b[c],c!==q)a.payload=c,d.push(a)}else d.push(a)});return d}function oa(a, -b){var d=[];c.a(a,function(a){a.id&&!b[a.id]&&d.push(a)});return d}function G(a,b){b=b||{};this.L=a;this.i=b.i||window.localStorage;this.h=b.I||c.bind(pa.error,pa);this.Ua=new qa(a,{i:this.i});this.qa=b.qa||q;this.G=[]}function qa(a,b){b=b||{};this.L=a;this.i=b.i||window.localStorage;this.Nb=b.Nb||100;this.$b=b.$b||2E3}function T(){this.Kb="submit"}function L(){this.Kb="click"}function E(){}function ra(a){var b=Fa,d=a.split("."),d=d[d.length-1];if(4a?"0"+a:a}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())};c.sa=function(a){var b={};c.a(a,function(a,f){c.Sa(a)&&0a?"0"+a:a}return a.getUTCFullYear()+"-"+b(a.getUTCMonth()+1)+"-"+b(a.getUTCDate())+"T"+b(a.getUTCHours())+":"+b(a.getUTCMinutes())+":"+b(a.getUTCSeconds())};c.ua=function(a){var b={};c.a(a,function(a,f){c.Ta(a)&&0=i;)h()}function d(){var a,b,d="",c;if('"'=== i)for(;h();){if('"'===i)return h(),d;if("\\"===i)if(h(),"u"===i){for(b=c=0;4>b;b+=1){a=parseInt(h(),16);if(!isFinite(a))break;c=16*c+a}d+=String.fromCharCode(c)}else if("string"===typeof e[i])d+=e[i];else break;else d+=i}g("Bad string")}function c(){var a;a="";"-"===i&&(a="-",h("-"));for(;"0"<=i&&"9">=i;)a+=i,h();if("."===i)for(a+=".";h()&&"0"<=i&&"9">=i;)a+=i;if("e"===i||"E"===i){a+=i;h();if("-"===i||"+"===i)a+=i,h();for(;"0"<=i&&"9">=i;)a+=i,h()}a=+a;if(isFinite(a))return a;g("Bad number")}function h(a){a&& -a!==i&&g("Expected '"+a+"' instead of '"+i+"'");i=r.charAt(s);s+=1;return i}function g(a){a=new SyntaxError(a);a.ud=s;a.text=r;throw a;}var s,i,e={'"':'"',"\\":"\\","/":"/",b:"\u0008",f:"\u000c",n:"\n",r:"\r",t:"\t"},r,p;p=function(){b();switch(i){case "{":var e;a:{var s,k={};if("{"===i){h("{");b();if("}"===i){h("}");e=k;break a}for(;i;){s=d();b();h(":");Object.hasOwnProperty.call(k,s)&&g('Duplicate key "'+s+'"');k[s]=p();b();if("}"===i){h("}");e=k;break a}h(",");b()}}g("Bad object")}return e;case "[":a:{e= -[];if("["===i){h("[");b();if("]"===i){h("]");s=e;break a}for(;i;){e.push(p());b();if("]"===i){h("]");s=e;break a}h(",");b()}}g("Bad array")}return s;case '"':return d();case "-":return c();default:return"0"<=i&&"9">=i?c():a()}};return function(a){r=a;s=0;i=" ";a=p();b();i&&g("Syntax error");return a}}();c.uc=function(a){var b,d,f,h,g=0,e=0,i="",i=[];if(!a)return a;a=c.sd(a);do b=a.charCodeAt(g++),d=a.charCodeAt(g++),f=a.charCodeAt(g++),h=b<<16|d<<8|f,b=h>>18&63,d=h>>12&63,f=h>>6&63,h&=63,i[e++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+ -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h);while(g=i?c():a()}};return function(a){p=a;r=0;i=" ";a=s();b();i&&g("Syntax error");return a}}();c.tc=function(a){var b,d,f,h,g=0,e=0,i="",i=[];if(!a)return a;a=c.rd(a);do b=a.charCodeAt(g++),d=a.charCodeAt(g++),f=a.charCodeAt(g++),h=b<<16|d<<8|f,b=h>>18&63,d=h>>12&63,f=h>>6&63,h&=63,i[e++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(b)+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(d)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(f)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h);while(ge?c++:i=127e?String.fromCharCode(e>>6|192,e&63|128):String.fromCharCode(e>>12|224,e>>6&63|128,e&63|128);i!==q&&(c>d&&(b+=a.substring(d,c)),b+=i,d=c=g+1)}c>d&&(b+=a.substring(d,a.length));return b};c.eb=function(){function a(){function a(b,d){var c,f=0;for(c=0;cv?(Qa.error("Timeout waiting for mutex on "+p+"; clearing lock. ["+k+"]"),j.removeItem(u),j.removeItem(o),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},x*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=q);var k=c||(new Date).getTime()+"|"+Math.random(),r=(new Date).getTime(), -p=this.L,x=this.Nb,v=this.$b,j=this.i,n=p+":X",o=p+":Y",u=p+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(t){b&&b(t)}};var pa=ga("batch");G.prototype.Ka=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.Ua.cb(c.bind(function(){var b;try{var c=this.Z();c.push(f);(b=this.Xa(c))&&this.G.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock",a);d&&d(D)},this), -this.qa)};G.prototype.Ac=function(a){var b=this.G.slice(0,a);if(b.lengthg.flushAfter&&!f[g.id]&&(g.Nc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Pc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.G=oa(this.G,d);var f=c.bind(function(){var b;try{var c=this.Z(),c=oa(c,d);if(b=this.Xa(c))for(var c=this.Z(),f=0;fe.length)this.$();else{this.Rb=m;var i=c.bind(function(e){this.Rb= -D;try{var g=D;if(a.ec)this.X.qd(s);else if(c.e(e)&&"timeout"===e.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(e)&&e.O&&(500<=e.O.status||429===e.O.status||"timeout"===e.error)){var i=2*this.ma,k=e.O.responseHeaders;if(k){var j=k["Retry-After"];j&&(i=1E3*parseInt(j,10)||i)}i=Math.min(6E5,i);this.h("Error; retry in "+i+" ms");this.Tb(i)}else if(c.e(e)&&e.O&&413===e.O.status)if(1v?(Qa.error("Timeout waiting for mutex on "+s+"; clearing lock. ["+k+"]"),j.removeItem(u),j.removeItem(o),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},x*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=q);var k=c||(new Date).getTime()+"|"+Math.random(),p=(new Date).getTime(), +s=this.L,x=this.Nb,v=this.$b,j=this.i,n=s+":X",o=s+":Y",u=s+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(t){b&&b(t)}};var pa=ga("batch");G.prototype.La=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.Ua.cb(c.bind(function(){var b;try{var c=this.$();c.push(f);(b=this.Xa(c))&&this.G.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock",a);d&&d(D)},this), +this.sa)};G.prototype.zc=function(a){var b=this.G.slice(0,a);if(b.lengthg.flushAfter&&!f[g.id]&&(g.Mc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Oc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.G=oa(this.G,d);var f=c.bind(function(){var b;try{var c=this.$(),c=oa(c,d);if(b=this.Xa(c))for(var c=this.$(),f=0;fe.length)this.aa();else{this.Rb=m;var i=c.bind(function(e){this.Rb= +D;try{var g=D;if(a.ec)this.Y.pd(r);else if(c.e(e)&&"timeout"===e.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(e)&&e.O&&(500<=e.O.status||429===e.O.status||"timeout"===e.error)){var i=2*this.na,k=e.O.responseHeaders;if(k){var j=k["Retry-After"];j&&(i=1E3*parseInt(j,10)||i)}i=Math.min(6E5,i);this.h("Error; retry in "+i+" ms");this.Tb(i)}else if(c.e(e)&&e.O&&413===e.O.status)if(1=v.timeout? -"timeout":"Bad HTTP status: "+v.status+" "+v.statusText,n.l(a),e&&(k?e({status:0,error:a,O:v}):e(0))};v.send(j)}catch(y){n.l(y),h=D}else j=u.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,t=u.getElementsByTagName("script")[0],t.parentNode.insertBefore(j,t);return h};e.prototype.xa=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a, -function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this):c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.nb=function(){return!!this.u.J};e.prototype.yb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.fb=this.fb||{J:{type:"events",D:"/"+b.track,Y:a+"_ev"},Wa:{type:"people",D:"/"+b.engage,Y:a+"_pp"},Oa:{type:"groups",D:"/"+ -b.groups,Y:a+"_gr"}}};e.prototype.Gc=function(){if(!this.nb()){var a=c.bind(function(a){return new C(a.Y,{A:this.config,Wc:c.bind(function(b,c,e){this.k(this.c("api_host")+a.D,this.hb(b),c,this.jb(e,b))},this),ha:c.bind(function(b){return this.lb("before_send_"+a.type,b)},this),I:this.c("error_reporter"),fd:c.bind(this.Za,this)})},this),b=this.yb();this.u={J:a(b.J),Wa:a(b.Wa),Oa:a(b.Oa)}}this.c("batch_autostart")&&this.Ya()};e.prototype.Ya=function(){this.kc=m;if(this.nb())this.Q=m,c.a(this.u,function(a){a.start()})}; -e.prototype.Za=function(){this.Q=D;c.a(this.u,function(a){a.stop();a.clear()})};e.prototype.push=function(a){this.xa([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.R.xc=m:this.ua=this.ua.concat(a)};e.prototype.hb=function(a){a=c.da(a);"base64"===this.c("api_payload_format")&&(a=c.uc(a));return{data:a}};e.prototype.Da=function(a,b){var d=c.truncate(a.data,255),e=a.D,h=a.Fa,g=a.dd,j=a.Xc||{},b=b||P,i=m,k=c.bind(function(){j.Zb||(d=this.lb("before_send_"+a.type,d));return d?(o.log("MIXPANEL REQUEST:"), -o.log(d),this.k(e,this.hb(d),j,this.jb(b,d))):q},this);this.Q&&!g?h.Ka(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=M(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=q);var d=d||{},h=d.transport;if(h)d.ab=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.g(a))this.l("No event name provided to mixpanel.track");else if(this.ib(a))e(0);else{b=c.extend({},b);b.token=this.c("token");var g=this.persistence.Qc(a);c.g(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3))); -this.mb();g=this.c("track_marketing")?c.info.Kc():{};b=c.extend({},c.info.W(),g,this.persistence.W(),this.N,b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Da({type:"events",data:{event:a,properties:b},D:this.c("api_host")+"/"+this.c("api_routes").track,Fa:this.u.J,dd:h,Xc:d},e)}});e.prototype.bd=M(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.rc= -M(function(a,b,c){var e=this.s(a);if(e===l){var h={};h[a]=[b];this.m(h)}else-1===e.indexOf(b)&&(e.push(b),this.m(h));return this.people.ba(a,b,c)});e.prototype.Rc=M(function(a,b,c){var e=this.s(a);if(e!==l){var h=e.indexOf(b);-1=v.timeout? +"timeout":"Bad HTTP status: "+v.status+" "+v.statusText,n.l(a),e&&(k?e({status:0,error:a,O:v}):e(0))};v.send(j)}catch(y){n.l(y),h=D}else j=u.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,t=u.getElementsByTagName("script")[0],t.parentNode.insertBefore(j,t);return h};e.prototype.za=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a, +function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this):c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.nb=function(){return!!this.u.J};e.prototype.yb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.fb=this.fb||{J:{type:"events",D:"/"+b.track,Z:a+"_ev"},Wa:{type:"people",D:"/"+b.engage,Z:a+"_pp"},Pa:{type:"groups",D:"/"+ +b.groups,Z:a+"_gr"}}};e.prototype.Fc=function(){if(!this.nb()){var a=c.bind(function(a){return new C(a.Z,{A:this.config,Vc:c.bind(function(b,c,e){this.k(this.c("api_host")+a.D,this.hb(b),c,this.jb(e,b))},this),ia:c.bind(function(b){return this.lb("before_send_"+a.type,b)},this),I:this.c("error_reporter"),ed:c.bind(this.Za,this)})},this),b=this.yb();this.u={J:a(b.J),Wa:a(b.Wa),Pa:a(b.Pa)}}this.c("batch_autostart")&&this.Ya()};e.prototype.Ya=function(){this.kc=m;if(this.nb())this.Q=m,c.a(this.u,function(a){a.start()})}; +e.prototype.Za=function(){this.Q=D;c.a(this.u,function(a){a.stop();a.clear()})};e.prototype.push=function(a){this.za([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.R.wc=m:this.wa=this.wa.concat(a)};e.prototype.hb=function(a){a=c.ea(a);"base64"===this.c("api_payload_format")&&(a=c.tc(a));return{data:a}};e.prototype.Ea=function(a,b){var d=c.truncate(a.data,255),e=a.D,h=a.Ga,g=a.cd,j=a.Wc||{},b=b||P,i=m,k=c.bind(function(){j.Zb||(d=this.lb("before_send_"+a.type,d));return d?(o.log("MIXPANEL REQUEST:"), +o.log(d),this.k(e,this.hb(d),j,this.jb(b,d))):q},this);this.Q&&!g?h.La(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=M(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=q);var d=d||{},h=d.transport;if(h)d.ab=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.g(a))this.l("No event name provided to mixpanel.track");else if(this.ib(a))e(0);else{b=c.extend({},b);b.token=this.c("token");var g=this.persistence.Pc(a);c.g(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3))); +this.mb();g=this.c("track_marketing")?c.info.Jc():{};b=c.extend({},c.info.X(),g,this.persistence.X(),this.N,b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Ea({type:"events",data:{event:a,properties:b},D:this.c("api_host")+"/"+this.c("api_routes").track,Ga:this.u.J,cd:h,Wc:d},e)}});e.prototype.ad=M(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.qc= +M(function(a,b,c){var e=this.s(a),h={};e===l?(h[a]=[b],this.m(h)):-1===e.indexOf(b)&&(e.push(b),h[a]=e,this.m(h));return this.people.ca(a,b,c)});e.prototype.Qc=M(function(a,b,c){var e=this.s(a);if(e!==l){var h=e.indexOf(b);-1(y.__SV||0)?o.H("Version mismatch; please ensure you're using the latest version of the Mixpanel code snippet."):(c.a(y._i,function(a){a&&c.isArray(a)&&(F[a[a.length-1]]=S.apply(this,a))}),Ba(),y.init(),c.a(F,function(a){a.ga()}),Aa())})()})(); +ignore_dnt:this.c("ignore_dnt")},b);c.localStorage.qa()||(b.persistence_type="cookie");return a(this.c("token"),{o:b.track,jd:b.track_event_name,kd:b.track_properties,Mb:b.persistence_type,Lb:b.cookie_prefix,rb:b.cookie_domain,sb:b.cookie_expiration,vc:b.cross_site_cookie,tb:b.cross_subdomain_cookie,Tc:b.secure_cookie,Ab:b.ignore_dnt})};e.prototype.Ib=function(a){a=c.extend({enable_persistence:m},a);this.T(Ha,a);this.fa(a)};e.prototype.Va=function(a){a=c.extend({clear_persistence:m,delete_user:m}, +a);a.delete_user&&this.people&&this.people.Ca()&&(this.people.wb(),this.people.ob());this.T(Ia,a);this.fa(a)};e.prototype.oa=function(a){return this.T(Ja,a)};e.prototype.V=function(a){return this.T(ta,a)};e.prototype.pb=function(a){a=c.extend({enable_persistence:m},a);this.T(La,a);this.fa(a)};e.prototype.l=function(a,b){o.error.apply(o.error,arguments);try{!b&&!(a instanceof Error)&&(a=Error(a)),this.c("error_reporter")(a,b)}catch(c){o.error(c)}};e.prototype.init=e.prototype.Ra;e.prototype.reset= +e.prototype.reset;e.prototype.disable=e.prototype.disable;e.prototype.time_event=e.prototype.gd;e.prototype.track=e.prototype.o;e.prototype.track_links=e.prototype.nd;e.prototype.track_forms=e.prototype.md;e.prototype.track_pageview=e.prototype.cc;e.prototype.register=e.prototype.m;e.prototype.register_once=e.prototype.w;e.prototype.unregister=e.prototype.da;e.prototype.identify=e.prototype.Qa;e.prototype.alias=e.prototype.rc;e.prototype.name_tag=e.prototype.Lc;e.prototype.set_config=e.prototype.Wb; +e.prototype.get_config=e.prototype.c;e.prototype.get_property=e.prototype.s;e.prototype.get_distinct_id=e.prototype.K;e.prototype.toString=e.prototype.toString;e.prototype.opt_out_tracking=e.prototype.Va;e.prototype.opt_in_tracking=e.prototype.Ib;e.prototype.has_opted_out_tracking=e.prototype.V;e.prototype.has_opted_in_tracking=e.prototype.oa;e.prototype.clear_opt_in_out_tracking=e.prototype.pb;e.prototype.get_group=e.prototype.Cc;e.prototype.set_group=e.prototype.ad;e.prototype.add_group=e.prototype.qc; +e.prototype.remove_group=e.prototype.Qc;e.prototype.track_with_groups=e.prototype.od;e.prototype.start_batch_senders=e.prototype.Ya;e.prototype.stop_batch_senders=e.prototype.Za;e.prototype.DEFAULT_API_ROUTES=B;n.prototype.properties=n.prototype.X;n.prototype.update_search_keyword=n.prototype.hc;n.prototype.update_referrer_info=n.prototype.bb;n.prototype.get_cross_subdomain=n.prototype.Bc;n.prototype.clear=n.prototype.clear;var F={};(function(){ca=1;y=w.mixpanel;c.g(y)?o.H('"mixpanel" object not initialized. Ensure you are using the latest version of the Mixpanel JS Library along with the snippet we provide.'): +y.__loaded||y.config&&y.persistence?o.H("The Mixpanel library has already been downloaded at least once. Ensure that the Mixpanel code snippet only appears once on the page (and is not double-loaded by a tag manager) in order to avoid errors."):1.1>(y.__SV||0)?o.H("Version mismatch; please ensure you're using the latest version of the Mixpanel code snippet."):(c.a(y._i,function(a){a&&c.isArray(a)&&(F[a[a.length-1]]=S.apply(this,a))}),Ba(),y.init(),c.a(F,function(a){a.ha()}),Aa())})()})(); })(); diff --git a/dist/mixpanel.umd.js b/dist/mixpanel.umd.js index 44ad99da..f0034206 100644 --- a/dist/mixpanel.umd.js +++ b/dist/mixpanel.umd.js @@ -6,7 +6,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -3582,13 +3582,13 @@ } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3604,12 +3604,13 @@ } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3782,17 +3783,11 @@ ); }; - MixpanelPersistence.prototype._load_prop = function(key) { + MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; - MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; - }; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -4039,7 +4034,7 @@ }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -4069,13 +4064,14 @@ }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4998,13 +4994,14 @@ */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -5742,7 +5739,7 @@ * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/examples/commonjs-browserify/bundle.js b/examples/commonjs-browserify/bundle.js index e12dacac..c11ecb15 100644 --- a/examples/commonjs-browserify/bundle.js +++ b/examples/commonjs-browserify/bundle.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -3579,13 +3579,13 @@ MixpanelPeople.prototype._flush = function( } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3601,12 +3601,13 @@ MixpanelPeople.prototype._flush = function( } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3779,17 +3780,11 @@ MixpanelPersistence.prototype.save = function() { ); }; -MixpanelPersistence.prototype._load_prop = function(key) { +MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; -MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; -}; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -4036,7 +4031,7 @@ MixpanelPersistence.prototype._pop_from_people_queue = function(queue, data) { }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -4066,13 +4061,14 @@ MixpanelPersistence.prototype._get_or_create_queue = function(queue, default_val }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -4995,13 +4991,14 @@ MixpanelLib.prototype.set_group = addOptOutCheckMixpanelLib(function(group_key, */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -5739,7 +5736,7 @@ MixpanelLib.prototype._run_hook = function(hook_name) { * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/examples/es2015-babelify/bundle.js b/examples/es2015-babelify/bundle.js index 753aee1b..ffdcb2b8 100644 --- a/examples/es2015-babelify/bundle.js +++ b/examples/es2015-babelify/bundle.js @@ -163,7 +163,7 @@ Object.defineProperty(exports, '__esModule', { }); var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; exports['default'] = Config; @@ -1590,13 +1590,14 @@ MixpanelLib.prototype.set_group = (0, _gdprUtils.addOptOutCheckMixpanelLib)(func */ MixpanelLib.prototype.add_group = (0, _gdprUtils.addOptOutCheckMixpanelLib)(function (group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -2324,7 +2325,7 @@ MixpanelLib.prototype._run_hook = function (hook_name) { * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function (property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function () { @@ -3410,13 +3411,13 @@ MixpanelPeople.prototype._flush = function (_set_callback, _add_callback, _appen } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(_apiActions.APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_utils._.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3432,12 +3433,13 @@ MixpanelPeople.prototype._flush = function (_set_callback, _add_callback, _appen } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(_apiActions.REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_utils._.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3606,17 +3608,11 @@ MixpanelPersistence.prototype.save = function () { this.storage.set(this.name, _utils._.JSONEncode(this['props']), this.expire_days, this.cross_subdomain, this.secure, this.cross_site, this.cookie_domain); }; -MixpanelPersistence.prototype._load_prop = function (key) { +MixpanelPersistence.prototype.load_prop = function (key) { this.load(); return this['props'][key]; }; -MixpanelPersistence.prototype._save_prop = function (key, val) { - this['props'][key] = val; - this.save(); - return val; -}; - MixpanelPersistence.prototype.remove = function () { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -3864,7 +3860,7 @@ MixpanelPersistence.prototype._pop_from_people_queue = function (queue, data) { }; MixpanelPersistence.prototype.load_queue = function (queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function (queue) { @@ -3894,13 +3890,14 @@ MixpanelPersistence.prototype._get_or_create_queue = function (queue, default_va }; MixpanelPersistence.prototype.set_event_timer = function (event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function (event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_utils._.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; diff --git a/examples/umd-webpack/bundle.js b/examples/umd-webpack/bundle.js index d542c3ac..d6f4802f 100644 --- a/examples/umd-webpack/bundle.js +++ b/examples/umd-webpack/bundle.js @@ -69,7 +69,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -3645,13 +3645,13 @@ } }; for (var i = $append_queue.length - 1; i >= 0; i--) { + $append_queue = this._mixpanel['persistence'].load_queue(APPEND_ACTION); $append_item = $append_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($append_item)) { _this.append($append_item, append_callback); } } - // Save the shortened append queue - _this._mixpanel['persistence'].save(); } // same for $remove @@ -3667,12 +3667,13 @@ } }; for (var j = $remove_queue.length - 1; j >= 0; j--) { + $remove_queue = this._mixpanel['persistence'].load_queue(REMOVE_ACTION); $remove_item = $remove_queue.pop(); + _this._mixpanel['persistence'].save(); if (!_.isEmptyObject($remove_item)) { _this.remove($remove_item, remove_callback); } } - _this._mixpanel['persistence'].save(); } }; @@ -3845,17 +3846,11 @@ ); }; - MixpanelPersistence.prototype._load_prop = function(key) { + MixpanelPersistence.prototype.load_prop = function(key) { this.load(); return this['props'][key]; }; - MixpanelPersistence.prototype._save_prop = function(key, val) { - this['props'][key] = val; - this.save(); - return val; - }; - MixpanelPersistence.prototype.remove = function() { // remove both domain and subdomain cookies this.storage.remove(this.name, false, this.cookie_domain); @@ -4102,7 +4097,7 @@ }; MixpanelPersistence.prototype.load_queue = function(queue) { - return this._load_prop(this._get_queue_key(queue)); + return this.load_prop(this._get_queue_key(queue)); }; MixpanelPersistence.prototype._get_queue_key = function(queue) { @@ -4132,13 +4127,14 @@ }; MixpanelPersistence.prototype.set_event_timer = function(event_name, timestamp) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; timers[event_name] = timestamp; - this._save_prop(EVENT_TIMERS_KEY, timers); + this['props'][EVENT_TIMERS_KEY] = timers; + this.save(); }; MixpanelPersistence.prototype.remove_event_timer = function(event_name) { - var timers = this._load_prop(EVENT_TIMERS_KEY) || {}; + var timers = this.load_prop(EVENT_TIMERS_KEY) || {}; var timestamp = timers[event_name]; if (!_.isUndefined(timestamp)) { delete this['props'][EVENT_TIMERS_KEY][event_name]; @@ -5061,13 +5057,14 @@ */ MixpanelLib.prototype.add_group = addOptOutCheckMixpanelLib(function(group_key, group_id, callback) { var old_values = this.get_property(group_key); + var prop = {}; if (old_values === undefined) { - var prop = {}; prop[group_key] = [group_id]; this.register(prop); } else { if (old_values.indexOf(group_id) === -1) { old_values.push(group_id); + prop[group_key] = old_values; this.register(prop); } } @@ -5805,7 +5802,7 @@ * @param {String} property_name The name of the super property you want to retrieve */ MixpanelLib.prototype.get_property = function(property_name) { - return this['persistence']['props'][property_name]; + return this['persistence'].load_prop([property_name]); }; MixpanelLib.prototype.toString = function() { diff --git a/src/config.js b/src/config.js index bea9a66f..f3825e51 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,6 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc1' + LIB_VERSION: '2.48.0-rc2' }; export default Config; From bd3e696b668eea4bfda3c43ca23644c76254f022 Mon Sep 17 00:00:00 2001 From: teddddd Date: Sat, 4 Nov 2023 04:59:36 +0000 Subject: [PATCH 19/26] test for reloading superprops from persistence whenever tracking --- tests/test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test.js b/tests/test.js index ea9a9c48..2f3a031e 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1472,6 +1472,24 @@ }), 'explicitly-set props take precedence over all superprops'); }); + test("props are loaded from persistence when tracking", function() { + var data = mixpanel.test.track('test', {'foo': 'bar'}); + ok(contains_obj(data.properties, {'foo': 'bar'})); + ok(!('a' in data.properties)); + + // initialize a separate instance with the same token (same persistence key) + // and set a super property in it + mixpanel.init(mixpanel.test.get_config('token'), {}, 'props_load_test'); + mixpanel.props_load_test.register({'a': 'b'}); + + // verify that the super property is now used in tracking from the original instance + data = mixpanel.test.track('test', {'foo': 'bar'}); + ok(contains_obj(data.properties, { + 'foo': 'bar', + 'a': 'b', + })); + }); + test("unregister (non-persistent)", 4, function() { mixpanel.test.register({'foo': 'persisted'}, {persistent: true}); mixpanel.test.unregister('foo', {persistent: false}); From b1ed747f413a2b53aaf6a8c06ab00d70c528262c Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 7 Nov 2023 22:22:17 +0000 Subject: [PATCH 20/26] v2.48.0 --- dist/mixpanel.amd.js | 2 +- dist/mixpanel.cjs.js | 2 +- dist/mixpanel.globals.js | 2 +- dist/mixpanel.min.js | 18 +++++++++--------- dist/mixpanel.umd.js | 2 +- examples/commonjs-browserify/bundle.js | 2 +- examples/es2015-babelify/bundle.js | 2 +- examples/umd-webpack/bundle.js | 2 +- src/config.js | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dist/mixpanel.amd.js b/dist/mixpanel.amd.js index 5d8c5672..3b9dc339 100644 --- a/dist/mixpanel.amd.js +++ b/dist/mixpanel.amd.js @@ -2,7 +2,7 @@ define(function () { 'use strict'; var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc2' + LIB_VERSION: '2.48.0' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file diff --git a/dist/mixpanel.cjs.js b/dist/mixpanel.cjs.js index 623689ad..e2a29510 100644 --- a/dist/mixpanel.cjs.js +++ b/dist/mixpanel.cjs.js @@ -2,7 +2,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc2' + LIB_VERSION: '2.48.0' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file diff --git a/dist/mixpanel.globals.js b/dist/mixpanel.globals.js index a1114206..f3d9ea7e 100644 --- a/dist/mixpanel.globals.js +++ b/dist/mixpanel.globals.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0-rc2' + LIB_VERSION: '2.48.0' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file diff --git a/dist/mixpanel.min.js b/dist/mixpanel.min.js index f3228121..4e519e62 100644 --- a/dist/mixpanel.min.js +++ b/dist/mixpanel.min.js @@ -39,18 +39,18 @@ return d},ja:function(a,b,d){return d||c.j(a," OPR/")?c.j(a,"Mini")?"Opera Mini" "Safari":c.j(a,"Android")?"Android Mobile":c.j(a,"Konqueror")?"Konqueror":c.j(a,"Firefox")?"Firefox":c.j(a,"MSIE")||c.j(a,"Trident/")?"Internet Explorer":c.j(a,"Gecko")?"Mozilla":""},Ha:function(a,b,d){b={"Internet Explorer Mobile":/rv:(\d+(\.\d+)?)/,"Microsoft Edge":/Edge?\/(\d+(\.\d+)?)/,Chrome:/Chrome\/(\d+(\.\d+)?)/,"Chrome iOS":/CriOS\/(\d+(\.\d+)?)/,"UC Browser":/(UCBrowser|UCWEB)\/(\d+(\.\d+)?)/,Safari:/Version\/(\d+(\.\d+)?)/,"Mobile Safari":/Version\/(\d+(\.\d+)?)/,Opera:/(Opera|OPR)\/(\d+(\.\d+)?)/, Firefox:/Firefox\/(\d+(\.\d+)?)/,"Firefox iOS":/FxiOS\/(\d+(\.\d+)?)/,Konqueror:/Konqueror:(\d+(\.\d+)?)/,BlackBerry:/BlackBerry (\d+(\.\d+)?)/,"Android Mobile":/android\s(\d+(\.\d+)?)/,"Samsung Internet":/SamsungBrowser\/(\d+(\.\d+)?)/,"Internet Explorer":/(rv:|MSIE )(\d+(\.\d+)?)/,Mozilla:/rv:(\d+(\.\d+)?)/}[c.info.ja(a,b,d)];if(b===l)return q;a=a.match(b);return!a?q:parseFloat(a[a.length-2])},Jb:function(){return/Windows/i.test(A)?/Phone/.test(A)||/WPDesktop/.test(A)?"Windows Phone":"Windows": /(iPhone|iPad|iPod)/.test(A)?"iOS":/Android/.test(A)?"Android":/(BlackBerry|PlayBook|BB10)/i.test(A)?"BlackBerry":/Mac/i.test(A)?"Mac OS X":/Linux/.test(A)?"Linux":/CrOS/.test(A)?"Chrome OS":""},xb:function(a){return/Windows Phone/i.test(a)||/WPDesktop/.test(a)?"Windows Phone":/iPad/.test(a)?"iPad":/iPod/.test(a)?"iPod Touch":/iPhone/.test(a)?"iPhone":/(BlackBerry|PlayBook|BB10)/i.test(a)?"BlackBerry":/Android/.test(a)?"Android":""},Ob:function(a){a=a.split("/");return 3<=a.length?a[2]:""},X:function(){return c.extend(c.ua({$os:c.info.Jb(), -$browser:c.info.ja(A,I.vendor,Y),$referrer:u.referrer,$referring_domain:c.info.Ob(u.referrer),$device:c.info.xb(A)}),{$current_url:w.location.href,$browser_version:c.info.Ha(A,I.vendor,Y),$screen_height:Z.height,$screen_width:Z.width,mp_lib:"web",$lib_version:"2.48.0-rc2",$insert_id:ea(),time:c.timestamp()/1E3})},Nc:function(){return c.extend(c.ua({$os:c.info.Jb(),$browser:c.info.ja(A,I.vendor,Y)}),{$browser_version:c.info.Ha(A,I.vendor,Y)})},Kc:function(){return c.ua({current_page_title:u.title, -current_domain:w.location.hostname,current_url_path:w.location.pathname,current_url_protocol:w.location.protocol,current_url_search:w.location.search})}};var Ga=/[a-z0-9][a-z0-9-]*\.[a-z]+$/i,Fa=/[a-z0-9][a-z0-9-]+\.[a-z.]{2,6}$/i,$=q,aa=q;if("undefined"!==typeof JSON)$=JSON.stringify,aa=JSON.parse;$=$||c.ea;aa=aa||c.P;c.toArray=c.M;c.isObject=c.e;c.JSONEncode=c.ea;c.JSONDecode=c.P;c.isBlockedUA=c.Eb;c.isEmptyObject=c.pa;c.info=c.info;c.info.device=c.info.xb;c.info.browser=c.info.ja;c.info.browserVersion= -c.info.Ha;c.info.properties=c.info.X;E.prototype.ma=function(){};E.prototype.Ma=function(){};E.prototype.Fa=function(){};E.prototype.Ra=function(a){this.Gb=a;return this};E.prototype.o=function(a,b,d,f){var h=this,g=c.xc(a);if(0===g.length)o.error("The DOM query ("+a+") returned 0 elements");else return c.a(g,function(a){c.Pb(a,this.Kb,function(a){var c={},g=h.ma(d,this),e=h.Gb.c("track_links_timeout");h.Ma(a,this,c);window.setTimeout(h.bc(f,g,c,m),e);h.Gb.o(b,g,h.bc(f,g,c))})},this),m};E.prototype.bc= -function(a,b,c,f){var f=f||D,h=this;return function(){if(!c.uc)c.uc=m,a&&a(f,b)===D||h.Fa(b,c,f)}};E.prototype.ma=function(a,b){return"function"===typeof a?a(b):c.extend({},a)};c.Db(L,E);L.prototype.ma=function(a,b){var c=L.fd.ma.apply(this,arguments);if(b.href)c.url=b.href;return c};L.prototype.Ma=function(a,b,c){c.Hb=2===a.which||a.metaKey||a.ctrlKey||"_blank"===b.target;c.href=b.href;c.Hb||a.preventDefault()};L.prototype.Fa=function(a,b){b.Hb||setTimeout(function(){window.location=b.href},0)}; -c.Db(T,E);T.prototype.Ma=function(a,b,c){c.element=b;a.preventDefault()};T.prototype.Fa=function(a,b){setTimeout(function(){b.element.submit()},0)};var Qa=ga("lock");qa.prototype.cb=function(a,b,c){function f(){j.setItem(u,"1");try{a()}finally{j.removeItem(u),j.getItem(o)===k&&j.removeItem(o),j.getItem(n)===k&&j.removeItem(n)}}function h(){j.setItem(n,k);e(g,function(){j.getItem(n)===k?f():i(function(){j.getItem(o)!==k?h():e(function(){return!j.getItem(u)},f)})})}function g(){var a=j.getItem(o);if(a&& -a!==k)return D;j.setItem(o,k);if(j.getItem(o)===k)return m;if(!U(j,m))throw Error("localStorage support dropped while acquiring lock");return D}function e(a,b){a()?b():i(function(){e(a,b)})}function i(a){(new Date).getTime()-p>v?(Qa.error("Timeout waiting for mutex on "+s+"; clearing lock. ["+k+"]"),j.removeItem(u),j.removeItem(o),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},x*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=q);var k=c||(new Date).getTime()+"|"+Math.random(),p=(new Date).getTime(), -s=this.L,x=this.Nb,v=this.$b,j=this.i,n=s+":X",o=s+":Y",u=s+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(t){b&&b(t)}};var pa=ga("batch");G.prototype.La=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.Ua.cb(c.bind(function(){var b;try{var c=this.$();c.push(f);(b=this.Xa(c))&&this.G.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock",a);d&&d(D)},this), -this.sa)};G.prototype.zc=function(a){var b=this.G.slice(0,a);if(b.lengthg.flushAfter&&!f[g.id]&&(g.Mc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Oc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.G=oa(this.G,d);var f=c.bind(function(){var b;try{var c=this.$(),c=oa(c,d);if(b=this.Xa(c))for(var c=this.$(),f=0;fv?(Qa.error("Timeout waiting for mutex on "+s+"; clearing lock. ["+k+"]"),j.removeItem(u),j.removeItem(o),h()):setTimeout(function(){try{a()}catch(c){b&&b(c)}},x*(Math.random()+0.1))}!c&&"function"!==typeof b&&(c=b,b=q);var k=c||(new Date).getTime()+"|"+Math.random(),p=(new Date).getTime(),s=this.L,x= +this.Nb,v=this.$b,j=this.i,n=s+":X",o=s+":Y",u=s+":Z";try{if(U(j,m))h();else throw Error("localStorage support check failed");}catch(t){b&&b(t)}};var pa=ga("batch");G.prototype.La=function(a,b,d){var f={id:ea(),flushAfter:(new Date).getTime()+2*b,payload:a};this.Ua.cb(c.bind(function(){var b;try{var c=this.$();c.push(f);(b=this.Xa(c))&&this.G.push(f)}catch(e){this.h("Error enqueueing item",a),b=D}d&&d(b)},this),c.bind(function(a){this.h("Error acquiring storage lock",a);d&&d(D)},this),this.sa)};G.prototype.zc= +function(a){var b=this.G.slice(0,a);if(b.lengthg.flushAfter&&!f[g.id]&&(g.Mc=m,b.push(g),b.length>=a))break}}}return b};G.prototype.Oc=function(a,b){var d={};c.a(a,function(a){d[a]=m});this.G=oa(this.G,d);var f=c.bind(function(){var b;try{var c=this.$(),c=oa(c,d);if(b=this.Xa(c))for(var c=this.$(),f=0;fe.length)this.aa();else{this.Rb=m;var i=c.bind(function(e){this.Rb= +d=(new Date).getTime(),f=this.C,h=this.Y.zc(f),e=[],r={};c.a(h,function(a){var b=a.payload;this.ia&&!a.Mc&&(b=this.ia(b));if(b){b.event&&b.properties&&(b.properties=c.extend({},b.properties,{mp_sent_by_lib_version:"2.48.0"}));var d=m,f=a.id;if(f){if(5<(this.F[f]||0))this.h("[dupe] item ID sent too many times, not sending",{item:a,C:h.length,hd:this.F[f]}),d=D}else this.h("[dupe] found item with no ID",{item:a});d&&e.push(b)}r[a.id]=b},this);if(1>e.length)this.aa();else{this.Rb=m;var i=c.bind(function(e){this.Rb= D;try{var g=D;if(a.ec)this.Y.pd(r);else if(c.e(e)&&"timeout"===e.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(e)&&e.O&&(500<=e.O.status||429===e.O.status||"timeout"===e.error)){var i=2*this.na,k=e.O.responseHeaders;if(k){var j=k["Retry-After"];j&&(i=1E3*parseInt(j,10)||i)}i=Math.min(6E5,i);this.h("Error; retry in "+i+" ms");this.Tb(i)}else if(c.e(e)&&e.O&&413===e.O.status)if(1 Date: Tue, 7 Nov 2023 22:35:39 +0000 Subject: [PATCH 21/26] changelog for 2.48.0 --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d8196f..f58f380c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,16 @@ +**2.48.0** (7 Nov 2023) +- API endpoint routes can now be configured individually (i.e. rename /track, /engage, /groups) +- Event properties object passed to mixpanel.track() will no longer be mutated +- Super properties are now reloaded from persistence when making every tracking call (i.e., kept fresh when another tab/window in the same browser has updated them) +- Extra failsafe behavior for trying to clear queued requests when localStorage doesn't work on startup, e.g., when localStorage is full so writes fail +- Block Chrome-Lighthouse user agent +- Fix for error in add_group() when adding a new group to an existing list + **2.47.0** (27 Apr 2023) - Collect richer marketing attribution properties for multi-touch attribution - New implementation of previously-deprecated track_pageview() method and init option to send automatically - Use performance.now when available for time-based entropy component of UUID-generation (thanks @adrianherd) -- looser API Host check for default JSON-payload sending to mipxanel.com hosts +- Looser API Host check for default JSON-payload sending to mipxanel.com hosts **2.46.0** (20 Mar 2023) - Updates for new identity management system From 3a2d8d98bdd29cd75f99849a736c4e8715a81df0 Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 7 Nov 2023 22:35:46 +0000 Subject: [PATCH 22/26] 2.48.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0a126b3..8f92a21a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mixpanel-browser", - "version": "2.47.0", + "version": "2.48.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mixpanel-browser", - "version": "2.47.0", + "version": "2.48.0", "license": "Apache-2.0", "devDependencies": { "babel": "6.5.2", diff --git a/package.json b/package.json index 27b39dff..0e0a90c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mixpanel-browser", - "version": "2.47.0", + "version": "2.48.0", "description": "The official Mixpanel JavaScript browser client library", "main": "dist/mixpanel.cjs.js", "directories": { From e55bfcae235f6f7de2c4de0c3919e8f8574990bd Mon Sep 17 00:00:00 2001 From: Chi Chova Date: Mon, 13 Nov 2023 20:25:29 +0000 Subject: [PATCH 23/26] Ensure UTMs persist in both unminified and minified code --- src/mixpanel-core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixpanel-core.js b/src/mixpanel-core.js index f546e84d..90c45e4a 100644 --- a/src/mixpanel-core.js +++ b/src/mixpanel-core.js @@ -359,7 +359,7 @@ MixpanelLib.prototype._loaded = function() { MixpanelLib.prototype._set_default_superprops = function() { this['persistence'].update_search_keyword(document.referrer); if (this.get_config('store_google')) { - this.register(_.info.campaignParams(), {persistent: false}); + this.register(_.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(document.referrer); From 4a114e634edcb60c89f3fb19e81b12af05ea139c Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 14 Nov 2023 05:08:58 +0000 Subject: [PATCH 24/26] rebuild 2.48.1 --- examples/commonjs-browserify/bundle.js | 4 ++-- examples/es2015-babelify/bundle.js | 4 ++-- examples/umd-webpack/bundle.js | 4 ++-- src/config.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/commonjs-browserify/bundle.js b/examples/commonjs-browserify/bundle.js index f10ea1f8..813bb959 100644 --- a/examples/commonjs-browserify/bundle.js +++ b/examples/commonjs-browserify/bundle.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -4417,7 +4417,7 @@ MixpanelLib.prototype._loaded = function() { MixpanelLib.prototype._set_default_superprops = function() { this['persistence'].update_search_keyword(document$1.referrer); if (this.get_config('store_google')) { - this.register(_.info.campaignParams(), {persistent: false}); + this.register(_.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(document$1.referrer); diff --git a/examples/es2015-babelify/bundle.js b/examples/es2015-babelify/bundle.js index 05fd7173..2affc2fa 100644 --- a/examples/es2015-babelify/bundle.js +++ b/examples/es2015-babelify/bundle.js @@ -163,7 +163,7 @@ Object.defineProperty(exports, '__esModule', { }); var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; exports['default'] = Config; @@ -1030,7 +1030,7 @@ MixpanelLib.prototype._loaded = function () { MixpanelLib.prototype._set_default_superprops = function () { this['persistence'].update_search_keyword(_utils.document.referrer); if (this.get_config('store_google')) { - this.register(_utils._.info.campaignParams(), { persistent: false }); + this.register(_utils._.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(_utils.document.referrer); diff --git a/examples/umd-webpack/bundle.js b/examples/umd-webpack/bundle.js index 826eb3a9..2e262265 100644 --- a/examples/umd-webpack/bundle.js +++ b/examples/umd-webpack/bundle.js @@ -69,7 +69,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -4483,7 +4483,7 @@ MixpanelLib.prototype._set_default_superprops = function() { this['persistence'].update_search_keyword(document$1.referrer); if (this.get_config('store_google')) { - this.register(_.info.campaignParams(), {persistent: false}); + this.register(_.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(document$1.referrer); diff --git a/src/config.js b/src/config.js index e902c423..dff6d699 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,6 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; export default Config; From ac18edb9deb84d71e64d7ba454fd1dcbacc4ca2b Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 14 Nov 2023 19:13:22 +0000 Subject: [PATCH 25/26] 2.48.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f92a21a..a2100686 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mixpanel-browser", - "version": "2.48.0", + "version": "2.48.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mixpanel-browser", - "version": "2.48.0", + "version": "2.48.1", "license": "Apache-2.0", "devDependencies": { "babel": "6.5.2", diff --git a/package.json b/package.json index 0e0a90c9..db276e7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mixpanel-browser", - "version": "2.48.0", + "version": "2.48.1", "description": "The official Mixpanel JavaScript browser client library", "main": "dist/mixpanel.cjs.js", "directories": { From 7d155e6fce7e59f3e13eb2e4d69b9905f10dbb36 Mon Sep 17 00:00:00 2001 From: teddddd Date: Tue, 14 Nov 2023 19:40:52 +0000 Subject: [PATCH 26/26] rebuild 2.48.1 + changelog --- CHANGELOG.md | 4 ++++ dist/mixpanel.amd.js | 4 ++-- dist/mixpanel.cjs.js | 4 ++-- dist/mixpanel.globals.js | 4 ++-- dist/mixpanel.min.js | 22 +++++++++++----------- dist/mixpanel.umd.js | 4 ++-- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f58f380c..f707f884 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +**2.48.1** (14 Nov 2023) +- UTM campaign properties will always be persisted super properties (fixes discrepancy between +minified and unminified package) + **2.48.0** (7 Nov 2023) - API endpoint routes can now be configured individually (i.e. rename /track, /engage, /groups) - Event properties object passed to mixpanel.track() will no longer be mutated diff --git a/dist/mixpanel.amd.js b/dist/mixpanel.amd.js index 3b9dc339..1d973811 100644 --- a/dist/mixpanel.amd.js +++ b/dist/mixpanel.amd.js @@ -2,7 +2,7 @@ define(function () { 'use strict'; var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -4416,7 +4416,7 @@ define(function () { 'use strict'; MixpanelLib.prototype._set_default_superprops = function() { this['persistence'].update_search_keyword(document$1.referrer); if (this.get_config('store_google')) { - this.register(_.info.campaignParams(), {persistent: false}); + this.register(_.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(document$1.referrer); diff --git a/dist/mixpanel.cjs.js b/dist/mixpanel.cjs.js index e2a29510..2deaecc3 100644 --- a/dist/mixpanel.cjs.js +++ b/dist/mixpanel.cjs.js @@ -2,7 +2,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -4416,7 +4416,7 @@ MixpanelLib.prototype._loaded = function() { MixpanelLib.prototype._set_default_superprops = function() { this['persistence'].update_search_keyword(document$1.referrer); if (this.get_config('store_google')) { - this.register(_.info.campaignParams(), {persistent: false}); + this.register(_.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(document$1.referrer); diff --git a/dist/mixpanel.globals.js b/dist/mixpanel.globals.js index f3d9ea7e..6050d0b6 100644 --- a/dist/mixpanel.globals.js +++ b/dist/mixpanel.globals.js @@ -3,7 +3,7 @@ var Config = { DEBUG: false, - LIB_VERSION: '2.48.0' + LIB_VERSION: '2.48.1' }; // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file @@ -4417,7 +4417,7 @@ MixpanelLib.prototype._set_default_superprops = function() { this['persistence'].update_search_keyword(document$1.referrer); if (this.get_config('store_google')) { - this.register(_.info.campaignParams(), {persistent: false}); + this.register(_.info.campaignParams()); } if (this.get_config('save_referrer')) { this['persistence'].update_referrer_info(document$1.referrer); diff --git a/dist/mixpanel.min.js b/dist/mixpanel.min.js index 4e519e62..53b88227 100644 --- a/dist/mixpanel.min.js +++ b/dist/mixpanel.min.js @@ -26,7 +26,7 @@ a!==i&&g("Expected '"+a+"' instead of '"+i+"'");i=p.charAt(r);r+=1;return i}func 128>e?c++:i=127e?String.fromCharCode(e>>6|192,e&63|128):String.fromCharCode(e>>12|224,e>>6&63|128,e&63|128);i!==q&&(c>d&&(b+=a.substring(d,c)),b+=i,d=c=g+1)}c>d&&(b+=a.substring(d,a.length));return b};c.eb=function(){function a(){function a(b,d){var c,f=0;for(c=0;ce.length)this.aa();else{this.Rb=m;var i=c.bind(function(e){this.Rb= +d=(new Date).getTime(),f=this.C,h=this.Y.zc(f),e=[],r={};c.a(h,function(a){var b=a.payload;this.ia&&!a.Mc&&(b=this.ia(b));if(b){b.event&&b.properties&&(b.properties=c.extend({},b.properties,{mp_sent_by_lib_version:"2.48.1"}));var d=m,f=a.id;if(f){if(5<(this.F[f]||0))this.h("[dupe] item ID sent too many times, not sending",{item:a,C:h.length,hd:this.F[f]}),d=D}else this.h("[dupe] found item with no ID",{item:a});d&&e.push(b)}r[a.id]=b},this);if(1>e.length)this.aa();else{this.Rb=m;var i=c.bind(function(e){this.Rb= D;try{var g=D;if(a.ec)this.Y.pd(r);else if(c.e(e)&&"timeout"===e.error&&(new Date).getTime()-d>=b)this.h("Network timeout; retrying"),this.flush();else if(c.e(e)&&e.O&&(500<=e.O.status||429===e.O.status||"timeout"===e.error)){var i=2*this.na,k=e.O.responseHeaders;if(k){var j=k["Retry-After"];j&&(i=1E3*parseInt(j,10)||i)}i=Math.min(6E5,i);this.h("Error; retry in "+i+" ms");this.Tb(i)}else if(c.e(e)&&e.O&&413===e.O.status)if(1=v.timeout? -"timeout":"Bad HTTP status: "+v.status+" "+v.statusText,n.l(a),e&&(k?e({status:0,error:a,O:v}):e(0))};v.send(j)}catch(y){n.l(y),h=D}else j=u.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,t=u.getElementsByTagName("script")[0],t.parentNode.insertBefore(j,t);return h};e.prototype.za=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a, -function(a){a&&(d=a[0],c.isArray(d)?g.push(a):"function"===typeof a?a.call(this):c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.nb=function(){return!!this.u.J};e.prototype.yb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.fb=this.fb||{J:{type:"events",D:"/"+b.track,Z:a+"_ev"},Wa:{type:"people",D:"/"+b.engage,Z:a+"_pp"},Pa:{type:"groups",D:"/"+ -b.groups,Z:a+"_gr"}}};e.prototype.Fc=function(){if(!this.nb()){var a=c.bind(function(a){return new C(a.Z,{A:this.config,Vc:c.bind(function(b,c,e){this.k(this.c("api_host")+a.D,this.hb(b),c,this.jb(e,b))},this),ia:c.bind(function(b){return this.lb("before_send_"+a.type,b)},this),I:this.c("error_reporter"),ed:c.bind(this.Za,this)})},this),b=this.yb();this.u={J:a(b.J),Wa:a(b.Wa),Pa:a(b.Pa)}}this.c("batch_autostart")&&this.Ya()};e.prototype.Ya=function(){this.kc=m;if(this.nb())this.Q=m,c.a(this.u,function(a){a.start()})}; -e.prototype.Za=function(){this.Q=D;c.a(this.u,function(a){a.stop();a.clear()})};e.prototype.push=function(a){this.za([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.R.wc=m:this.wa=this.wa.concat(a)};e.prototype.hb=function(a){a=c.ea(a);"base64"===this.c("api_payload_format")&&(a=c.tc(a));return{data:a}};e.prototype.Ea=function(a,b){var d=c.truncate(a.data,255),e=a.D,h=a.Ga,g=a.cd,j=a.Wc||{},b=b||P,i=m,k=c.bind(function(){j.Zb||(d=this.lb("before_send_"+a.type,d));return d?(o.log("MIXPANEL REQUEST:"), +this.m(c.info.ka());this.c("save_referrer")&&this.persistence.bb(u.referrer)};e.prototype.mc=function(){c.a(this.xa,function(a){this.Da.apply(this,a)},this);this.V()||c.a(this.ya,function(a){this.k.apply(this,a)},this);delete this.xa;delete this.ya};e.prototype.Da=function(a,b){if(this.c("img"))return this.l("You can't use DOM tracking functions with img = true."),D;if(!la)return this.xa.push([a,b]),D;var c=(new a).Ra(this);return c.o.apply(c,b)};e.prototype.jb=function(a,b){if(c.g(a))return q;if(O)return function(c){a(c, +b)};var d=this._jsc,e=""+Math.floor(1E8*Math.random()),h=this.c("callback_fn")+"["+e+"]";d[e]=function(c){delete d[e];a(c,b)};return h};e.prototype.k=function(a,b,d,e){var h=m;if(ma)return this.ya.push(arguments),h;var g={method:this.c("api_method"),ab:this.c("api_transport"),ic:this.c("verbose")},j=q;if(!e&&(c.Sa(d)||"string"===typeof d))e=d,d=q;d=c.extend(g,d||{});if(!O)d.method="GET";var g="POST"===d.method,i=ba&&g&&"sendbeacon"===d.ab.toLowerCase(),k=d.ic;b.verbose&&(k=m);this.c("test")&&(b.test= +1);k&&(b.verbose=1);this.c("img")&&(b.img=1);if(!O)if(e)b.callback=e;else if(k||this.c("test"))b.callback="(function(){})";b.ip=this.c("ip")?1:0;b._=(new Date).getTime().toString();g&&(j="data="+encodeURIComponent(b.data),delete b.data);var a=a+("?"+c.jc(b)),n=this;if("img"in b)j=u.createElement("img"),j.src=a,u.body.appendChild(j);else if(i){try{h=ba(a,j)}catch(s){n.l(s),h=D}try{e&&e(h?1:0)}catch(o){n.l(o)}}else if(O)try{var v=new XMLHttpRequest;v.open(d.method,a,m);var t=this.c("xhr_headers");g&& +(t["Content-Type"]="application/x-www-form-urlencoded");c.a(t,function(a,b){v.setRequestHeader(b,a)});if(d.ac&&"undefined"!==typeof v.timeout){v.timeout=d.ac;var w=(new Date).getTime()}v.withCredentials=m;v.onreadystatechange=function(){if(4===v.readyState)if(200===v.status){if(e)if(k){var a;try{a=c.P(v.responseText)}catch(b){if(n.l(b),d.Ec)a=v.responseText;else return}e(a)}else e(Number(v.responseText))}else a=v.timeout&&!v.status&&(new Date).getTime()-w>=v.timeout?"timeout":"Bad HTTP status: "+ +v.status+" "+v.statusText,n.l(a),e&&(k?e({status:0,error:a,O:v}):e(0))};v.send(j)}catch(y){n.l(y),h=D}else j=u.createElement("script"),j.type="text/javascript",j.async=m,j.defer=m,j.src=a,t=u.getElementsByTagName("script")[0],t.parentNode.insertBefore(j,t);return h};e.prototype.za=function(a){function b(a,b){c.a(a,function(a){if(c.isArray(a[0])){var d=b;c.a(a,function(a){d=d[a[0]].apply(d,a.slice(1))})}else this[a[0]].apply(this,a.slice(1))},b)}var d,e=[],h=[],g=[];c.a(a,function(a){a&&(d=a[0],c.isArray(d)? +g.push(a):"function"===typeof a?a.call(this):c.isArray(a)&&"alias"===d?e.push(a):c.isArray(a)&&-1!==d.indexOf("track")&&"function"===typeof this[d]?g.push(a):h.push(a))},this);b(e,this);b(h,this);b(g,this)};e.prototype.nb=function(){return!!this.u.J};e.prototype.yb=function(){var a="__mpq_"+this.c("token"),b=this.c("api_routes");return this.fb=this.fb||{J:{type:"events",D:"/"+b.track,Z:a+"_ev"},Wa:{type:"people",D:"/"+b.engage,Z:a+"_pp"},Pa:{type:"groups",D:"/"+b.groups,Z:a+"_gr"}}};e.prototype.Fc= +function(){if(!this.nb()){var a=c.bind(function(a){return new C(a.Z,{A:this.config,Vc:c.bind(function(b,c,e){this.k(this.c("api_host")+a.D,this.hb(b),c,this.jb(e,b))},this),ia:c.bind(function(b){return this.lb("before_send_"+a.type,b)},this),I:this.c("error_reporter"),ed:c.bind(this.Za,this)})},this),b=this.yb();this.u={J:a(b.J),Wa:a(b.Wa),Pa:a(b.Pa)}}this.c("batch_autostart")&&this.Ya()};e.prototype.Ya=function(){this.kc=m;if(this.nb())this.Q=m,c.a(this.u,function(a){a.start()})};e.prototype.Za= +function(){this.Q=D;c.a(this.u,function(a){a.stop();a.clear()})};e.prototype.push=function(a){this.za([a])};e.prototype.disable=function(a){"undefined"===typeof a?this.R.wc=m:this.wa=this.wa.concat(a)};e.prototype.hb=function(a){a=c.ea(a);"base64"===this.c("api_payload_format")&&(a=c.tc(a));return{data:a}};e.prototype.Ea=function(a,b){var d=c.truncate(a.data,255),e=a.D,h=a.Ga,g=a.cd,j=a.Wc||{},b=b||P,i=m,k=c.bind(function(){j.Zb||(d=this.lb("before_send_"+a.type,d));return d?(o.log("MIXPANEL REQUEST:"), o.log(d),this.k(e,this.hb(d),j,this.jb(b,d))):q},this);this.Q&&!g?h.La(d,function(a){a?b(1,d):k()}):i=k();return i&&d};e.prototype.o=M(function(a,b,d,e){!e&&"function"===typeof d&&(e=d,d=q);var d=d||{},h=d.transport;if(h)d.ab=h;h=d.send_immediately;"function"!==typeof e&&(e=P);if(c.g(a))this.l("No event name provided to mixpanel.track");else if(this.ib(a))e(0);else{b=c.extend({},b);b.token=this.c("token");var g=this.persistence.Pc(a);c.g(g)||(b.$duration=parseFloat((((new Date).getTime()-g)/1E3).toFixed(3))); this.mb();g=this.c("track_marketing")?c.info.Jc():{};b=c.extend({},c.info.X(),g,this.persistence.X(),this.N,b);g=this.c("property_blacklist");c.isArray(g)?c.a(g,function(a){delete b[a]}):this.l("Invalid value for property_blacklist config: "+g);return this.Ea({type:"events",data:{event:a,properties:b},D:this.c("api_host")+"/"+this.c("api_routes").track,Ga:this.u.J,cd:h,Wc:d},e)}});e.prototype.ad=M(function(a,b,d){c.isArray(b)||(b=[b]);var e={};e[a]=b;this.m(e);return this.people.set(a,b,d)});e.prototype.qc= M(function(a,b,c){var e=this.s(a),h={};e===l?(h[a]=[b],this.m(h)):-1===e.indexOf(b)&&(e.push(b),h[a]=e,this.m(h));return this.people.ca(a,b,c)});e.prototype.Qc=M(function(a,b,c){var e=this.s(a);if(e!==l){var h=e.indexOf(b);-1