mixpanel-browser 2.45.0 → 2.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/README.md +1 -1
- package/build.sh +2 -0
- package/dist/mixpanel.amd.js +93 -34
- package/dist/mixpanel.cjs.js +93 -34
- package/dist/mixpanel.globals.js +93 -34
- package/dist/mixpanel.min.js +100 -99
- package/dist/mixpanel.umd.js +93 -34
- package/doc/readme.io/javascript-full-api-reference.md +3 -55
- package/doc/template.md +1 -1
- package/package.json +5 -5
- package/src/config.js +1 -1
- package/src/mixpanel-core.js +14 -5
- package/src/mixpanel-people.js +29 -27
- package/src/request-batcher.js +50 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
**2.46.0** (20 Mar 2023)
|
|
2
|
+
- Updates for new identity management system
|
|
3
|
+
- More aggressive deduplication within batch sender
|
|
4
|
+
|
|
1
5
|
**2.45.0** (17 Feb 2022)
|
|
2
6
|
- Remove all code related to in-app messaging feature
|
|
3
7
|
- Add `error_reporter` config option for user-configurable handling of errors
|
|
@@ -5,7 +9,7 @@
|
|
|
5
9
|
- Fixes for some batch/retry edge cases where localStorage write failures resulted in duplicate sends
|
|
6
10
|
|
|
7
11
|
**2.43.0** (5 Jan 2022)
|
|
8
|
-
- Support plain JSON tracking payloads (no base64-encoding) and use as default when
|
|
12
|
+
- Support plain JSON tracking payloads (no base64-encoding) and use as default when sending to *.mixpanel.com API hosts
|
|
9
13
|
|
|
10
14
|
**2.42.1** (20 Dec 2021)
|
|
11
15
|
- Add new crawler user agents to blocked list (ahrefsbot, petalbot)
|
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ Mixpanel production releases are tested against a large matrix of browsers and o
|
|
|
72
72
|
## Generating and publishing documentation
|
|
73
73
|
- Create bundled source build: `npm run build-dist`
|
|
74
74
|
- Generate Markdown: `npm run dox` (result is at `doc/readme.io/javascript-full-api-reference.md`)
|
|
75
|
-
- Publish to readme.io via the [rdme](https://www.npmjs.com/package/rdme) util: `RDME_API_KEY=<API_KEY> npm run dox-publish`
|
|
75
|
+
- Publish to readme.io via the [rdme](https://www.npmjs.com/package/rdme) util: `RDME_API_KEY=<API_KEY> RDME_DOC_VERSION=<version> npm run dox-publish`
|
|
76
76
|
|
|
77
77
|
## Thanks
|
|
78
78
|
For patches and support: @bohanyang, @dehau, @drubin, @D1plo1d, @feychenie, @mogstad, @pfhayes, @sandorfr, @stefansedich, @gfx, @pkaminski, @austince, @danielbaker, @mkdai, @wolever, @dpraul, @chriszamierowski, @JoaoGomesTW
|
package/build.sh
CHANGED
package/dist/mixpanel.amd.js
CHANGED
|
@@ -2,7 +2,7 @@ define(function () { 'use strict';
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.46.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -2295,6 +2295,9 @@ define(function () { 'use strict';
|
|
|
2295
2295
|
|
|
2296
2296
|
this.stopped = !this.libConfig['batch_autostart'];
|
|
2297
2297
|
this.consecutiveRemovalFailures = 0;
|
|
2298
|
+
|
|
2299
|
+
// extra client-side dedupe
|
|
2300
|
+
this.itemIdsSentSuccessfully = {};
|
|
2298
2301
|
};
|
|
2299
2302
|
|
|
2300
2303
|
/**
|
|
@@ -2387,7 +2390,34 @@ define(function () { 'use strict';
|
|
|
2387
2390
|
payload = this.beforeSendHook(payload);
|
|
2388
2391
|
}
|
|
2389
2392
|
if (payload) {
|
|
2390
|
-
|
|
2393
|
+
// mp_sent_by_lib_version prop captures which lib version actually
|
|
2394
|
+
// sends each event (regardless of which version originally queued
|
|
2395
|
+
// it for sending)
|
|
2396
|
+
if (payload['event'] && payload['properties']) {
|
|
2397
|
+
payload['properties'] = _.extend(
|
|
2398
|
+
{},
|
|
2399
|
+
payload['properties'],
|
|
2400
|
+
{'mp_sent_by_lib_version': Config.LIB_VERSION}
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
var addPayload = true;
|
|
2404
|
+
var itemId = item['id'];
|
|
2405
|
+
if (itemId) {
|
|
2406
|
+
if ((this.itemIdsSentSuccessfully[itemId] || 0) > 5) {
|
|
2407
|
+
this.reportError('[dupe] item ID sent too many times, not sending', {
|
|
2408
|
+
item: item,
|
|
2409
|
+
batchSize: batch.length,
|
|
2410
|
+
timesSent: this.itemIdsSentSuccessfully[itemId]
|
|
2411
|
+
});
|
|
2412
|
+
addPayload = false;
|
|
2413
|
+
}
|
|
2414
|
+
} else {
|
|
2415
|
+
this.reportError('[dupe] found item with no ID', {item: item});
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
if (addPayload) {
|
|
2419
|
+
dataForRequest.push(payload);
|
|
2420
|
+
}
|
|
2391
2421
|
}
|
|
2392
2422
|
transformedItems[item['id']] = payload;
|
|
2393
2423
|
}, this);
|
|
@@ -2470,6 +2500,24 @@ define(function () { 'use strict';
|
|
|
2470
2500
|
}
|
|
2471
2501
|
}, this)
|
|
2472
2502
|
);
|
|
2503
|
+
|
|
2504
|
+
// client-side dedupe
|
|
2505
|
+
_.each(batch, _.bind(function(item) {
|
|
2506
|
+
var itemId = item['id'];
|
|
2507
|
+
if (itemId) {
|
|
2508
|
+
this.itemIdsSentSuccessfully[itemId] = this.itemIdsSentSuccessfully[itemId] || 0;
|
|
2509
|
+
this.itemIdsSentSuccessfully[itemId]++;
|
|
2510
|
+
if (this.itemIdsSentSuccessfully[itemId] > 5) {
|
|
2511
|
+
this.reportError('[dupe] item ID sent too many times', {
|
|
2512
|
+
item: item,
|
|
2513
|
+
batchSize: batch.length,
|
|
2514
|
+
timesSent: this.itemIdsSentSuccessfully[itemId]
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
} else {
|
|
2518
|
+
this.reportError('[dupe] found item with no ID while removing', {item: item});
|
|
2519
|
+
}
|
|
2520
|
+
}, this));
|
|
2473
2521
|
}
|
|
2474
2522
|
|
|
2475
2523
|
} catch(err) {
|
|
@@ -3315,24 +3363,25 @@ define(function () { 'use strict';
|
|
|
3315
3363
|
});
|
|
3316
3364
|
|
|
3317
3365
|
/*
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3366
|
+
* Record that you have charged the current user a certain amount
|
|
3367
|
+
* of money. Charges recorded with track_charge() will appear in the
|
|
3368
|
+
* Mixpanel revenue report.
|
|
3369
|
+
*
|
|
3370
|
+
* ### Usage:
|
|
3371
|
+
*
|
|
3372
|
+
* // charge a user $50
|
|
3373
|
+
* mixpanel.people.track_charge(50);
|
|
3374
|
+
*
|
|
3375
|
+
* // charge a user $30.50 on the 2nd of january
|
|
3376
|
+
* mixpanel.people.track_charge(30.50, {
|
|
3377
|
+
* '$time': new Date('jan 1 2012')
|
|
3378
|
+
* });
|
|
3379
|
+
*
|
|
3380
|
+
* @param {Number} amount The amount of money charged to the current user
|
|
3381
|
+
* @param {Object} [properties] An associative array of properties associated with the charge
|
|
3382
|
+
* @param {Function} [callback] If provided, the callback will be called when the server responds
|
|
3383
|
+
* @deprecated
|
|
3384
|
+
*/
|
|
3336
3385
|
MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(amount, properties, callback) {
|
|
3337
3386
|
if (!_.isNumber(amount)) {
|
|
3338
3387
|
amount = parseFloat(amount);
|
|
@@ -3348,15 +3397,16 @@ define(function () { 'use strict';
|
|
|
3348
3397
|
});
|
|
3349
3398
|
|
|
3350
3399
|
/*
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3400
|
+
* Permanently clear all revenue report transactions from the
|
|
3401
|
+
* current user's people analytics profile.
|
|
3402
|
+
*
|
|
3403
|
+
* ### Usage:
|
|
3404
|
+
*
|
|
3405
|
+
* mixpanel.people.clear_charges();
|
|
3406
|
+
*
|
|
3407
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3408
|
+
* @deprecated
|
|
3409
|
+
*/
|
|
3360
3410
|
MixpanelPeople.prototype.clear_charges = function(callback) {
|
|
3361
3411
|
return this.set('$transactions', [], callback);
|
|
3362
3412
|
};
|
|
@@ -4045,6 +4095,7 @@ define(function () { 'use strict';
|
|
|
4045
4095
|
/** @const */ var PRIMARY_INSTANCE_NAME = 'mixpanel';
|
|
4046
4096
|
/** @const */ var PAYLOAD_TYPE_BASE64 = 'base64';
|
|
4047
4097
|
/** @const */ var PAYLOAD_TYPE_JSON = 'json';
|
|
4098
|
+
/** @const */ var DEVICE_ID_PREFIX = '$device:';
|
|
4048
4099
|
|
|
4049
4100
|
|
|
4050
4101
|
/*
|
|
@@ -4292,7 +4343,7 @@ define(function () { 'use strict';
|
|
|
4292
4343
|
// or the device id if something was already stored
|
|
4293
4344
|
// in the persitence
|
|
4294
4345
|
this.register_once({
|
|
4295
|
-
'distinct_id': uuid,
|
|
4346
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
4296
4347
|
'$device_id': uuid
|
|
4297
4348
|
}, '');
|
|
4298
4349
|
}
|
|
@@ -5218,7 +5269,15 @@ define(function () { 'use strict';
|
|
|
5218
5269
|
// _unset_callback:function A callback to be run if and when the People unset queue is flushed
|
|
5219
5270
|
|
|
5220
5271
|
var previous_distinct_id = this.get_distinct_id();
|
|
5221
|
-
|
|
5272
|
+
if (new_distinct_id && previous_distinct_id !== new_distinct_id) {
|
|
5273
|
+
// we allow the following condition if previous distinct_id is same as new_distinct_id
|
|
5274
|
+
// so that you can force flush people updates for anonymous profiles.
|
|
5275
|
+
if (typeof new_distinct_id === 'string' && new_distinct_id.indexOf(DEVICE_ID_PREFIX) === 0) {
|
|
5276
|
+
this.report_error('distinct_id cannot have $device: prefix');
|
|
5277
|
+
return -1;
|
|
5278
|
+
}
|
|
5279
|
+
this.register({'$user_id': new_distinct_id});
|
|
5280
|
+
}
|
|
5222
5281
|
|
|
5223
5282
|
if (!this.get_property('$device_id')) {
|
|
5224
5283
|
// The persisted distinct id might not actually be a device id at all
|
|
@@ -5259,7 +5318,7 @@ define(function () { 'use strict';
|
|
|
5259
5318
|
this._flags.identify_called = false;
|
|
5260
5319
|
var uuid = _.UUID();
|
|
5261
5320
|
this.register_once({
|
|
5262
|
-
'distinct_id': uuid,
|
|
5321
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
5263
5322
|
'$device_id': uuid
|
|
5264
5323
|
}, '');
|
|
5265
5324
|
};
|
|
@@ -5384,8 +5443,8 @@ define(function () { 'use strict';
|
|
|
5384
5443
|
* // batching or retry mechanisms.
|
|
5385
5444
|
* api_transport: 'XHR'
|
|
5386
5445
|
*
|
|
5387
|
-
* //
|
|
5388
|
-
* batch_requests:
|
|
5446
|
+
* // request-batching/queueing/retry
|
|
5447
|
+
* batch_requests: true,
|
|
5389
5448
|
*
|
|
5390
5449
|
* // maximum number of events/updates to send in a single
|
|
5391
5450
|
* // network request
|
package/dist/mixpanel.cjs.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Config = {
|
|
4
4
|
DEBUG: false,
|
|
5
|
-
LIB_VERSION: '2.
|
|
5
|
+
LIB_VERSION: '2.46.0'
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -2295,6 +2295,9 @@ var RequestBatcher = function(storageKey, options) {
|
|
|
2295
2295
|
|
|
2296
2296
|
this.stopped = !this.libConfig['batch_autostart'];
|
|
2297
2297
|
this.consecutiveRemovalFailures = 0;
|
|
2298
|
+
|
|
2299
|
+
// extra client-side dedupe
|
|
2300
|
+
this.itemIdsSentSuccessfully = {};
|
|
2298
2301
|
};
|
|
2299
2302
|
|
|
2300
2303
|
/**
|
|
@@ -2387,7 +2390,34 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2387
2390
|
payload = this.beforeSendHook(payload);
|
|
2388
2391
|
}
|
|
2389
2392
|
if (payload) {
|
|
2390
|
-
|
|
2393
|
+
// mp_sent_by_lib_version prop captures which lib version actually
|
|
2394
|
+
// sends each event (regardless of which version originally queued
|
|
2395
|
+
// it for sending)
|
|
2396
|
+
if (payload['event'] && payload['properties']) {
|
|
2397
|
+
payload['properties'] = _.extend(
|
|
2398
|
+
{},
|
|
2399
|
+
payload['properties'],
|
|
2400
|
+
{'mp_sent_by_lib_version': Config.LIB_VERSION}
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
var addPayload = true;
|
|
2404
|
+
var itemId = item['id'];
|
|
2405
|
+
if (itemId) {
|
|
2406
|
+
if ((this.itemIdsSentSuccessfully[itemId] || 0) > 5) {
|
|
2407
|
+
this.reportError('[dupe] item ID sent too many times, not sending', {
|
|
2408
|
+
item: item,
|
|
2409
|
+
batchSize: batch.length,
|
|
2410
|
+
timesSent: this.itemIdsSentSuccessfully[itemId]
|
|
2411
|
+
});
|
|
2412
|
+
addPayload = false;
|
|
2413
|
+
}
|
|
2414
|
+
} else {
|
|
2415
|
+
this.reportError('[dupe] found item with no ID', {item: item});
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
if (addPayload) {
|
|
2419
|
+
dataForRequest.push(payload);
|
|
2420
|
+
}
|
|
2391
2421
|
}
|
|
2392
2422
|
transformedItems[item['id']] = payload;
|
|
2393
2423
|
}, this);
|
|
@@ -2470,6 +2500,24 @@ RequestBatcher.prototype.flush = function(options) {
|
|
|
2470
2500
|
}
|
|
2471
2501
|
}, this)
|
|
2472
2502
|
);
|
|
2503
|
+
|
|
2504
|
+
// client-side dedupe
|
|
2505
|
+
_.each(batch, _.bind(function(item) {
|
|
2506
|
+
var itemId = item['id'];
|
|
2507
|
+
if (itemId) {
|
|
2508
|
+
this.itemIdsSentSuccessfully[itemId] = this.itemIdsSentSuccessfully[itemId] || 0;
|
|
2509
|
+
this.itemIdsSentSuccessfully[itemId]++;
|
|
2510
|
+
if (this.itemIdsSentSuccessfully[itemId] > 5) {
|
|
2511
|
+
this.reportError('[dupe] item ID sent too many times', {
|
|
2512
|
+
item: item,
|
|
2513
|
+
batchSize: batch.length,
|
|
2514
|
+
timesSent: this.itemIdsSentSuccessfully[itemId]
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
} else {
|
|
2518
|
+
this.reportError('[dupe] found item with no ID while removing', {item: item});
|
|
2519
|
+
}
|
|
2520
|
+
}, this));
|
|
2473
2521
|
}
|
|
2474
2522
|
|
|
2475
2523
|
} catch(err) {
|
|
@@ -3315,24 +3363,25 @@ MixpanelPeople.prototype.union = addOptOutCheckMixpanelPeople(function(list_name
|
|
|
3315
3363
|
});
|
|
3316
3364
|
|
|
3317
3365
|
/*
|
|
3318
|
-
* Record that you have charged the current user a certain amount
|
|
3319
|
-
* of money. Charges recorded with track_charge() will appear in the
|
|
3320
|
-
* Mixpanel revenue report.
|
|
3321
|
-
*
|
|
3322
|
-
* ### Usage:
|
|
3323
|
-
*
|
|
3324
|
-
* // charge a user $50
|
|
3325
|
-
* mixpanel.people.track_charge(50);
|
|
3326
|
-
*
|
|
3327
|
-
* // charge a user $30.50 on the 2nd of january
|
|
3328
|
-
* mixpanel.people.track_charge(30.50, {
|
|
3329
|
-
* '$time': new Date('jan 1 2012')
|
|
3330
|
-
* });
|
|
3331
|
-
*
|
|
3332
|
-
* @param {Number} amount The amount of money charged to the current user
|
|
3333
|
-
* @param {Object} [properties] An associative array of properties associated with the charge
|
|
3334
|
-
* @param {Function} [callback] If provided, the callback will be called when the server responds
|
|
3335
|
-
|
|
3366
|
+
* Record that you have charged the current user a certain amount
|
|
3367
|
+
* of money. Charges recorded with track_charge() will appear in the
|
|
3368
|
+
* Mixpanel revenue report.
|
|
3369
|
+
*
|
|
3370
|
+
* ### Usage:
|
|
3371
|
+
*
|
|
3372
|
+
* // charge a user $50
|
|
3373
|
+
* mixpanel.people.track_charge(50);
|
|
3374
|
+
*
|
|
3375
|
+
* // charge a user $30.50 on the 2nd of january
|
|
3376
|
+
* mixpanel.people.track_charge(30.50, {
|
|
3377
|
+
* '$time': new Date('jan 1 2012')
|
|
3378
|
+
* });
|
|
3379
|
+
*
|
|
3380
|
+
* @param {Number} amount The amount of money charged to the current user
|
|
3381
|
+
* @param {Object} [properties] An associative array of properties associated with the charge
|
|
3382
|
+
* @param {Function} [callback] If provided, the callback will be called when the server responds
|
|
3383
|
+
* @deprecated
|
|
3384
|
+
*/
|
|
3336
3385
|
MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(amount, properties, callback) {
|
|
3337
3386
|
if (!_.isNumber(amount)) {
|
|
3338
3387
|
amount = parseFloat(amount);
|
|
@@ -3348,15 +3397,16 @@ MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(am
|
|
|
3348
3397
|
});
|
|
3349
3398
|
|
|
3350
3399
|
/*
|
|
3351
|
-
* Permanently clear all revenue report transactions from the
|
|
3352
|
-
* current user's people analytics profile.
|
|
3353
|
-
*
|
|
3354
|
-
* ### Usage:
|
|
3355
|
-
*
|
|
3356
|
-
* mixpanel.people.clear_charges();
|
|
3357
|
-
*
|
|
3358
|
-
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3359
|
-
|
|
3400
|
+
* Permanently clear all revenue report transactions from the
|
|
3401
|
+
* current user's people analytics profile.
|
|
3402
|
+
*
|
|
3403
|
+
* ### Usage:
|
|
3404
|
+
*
|
|
3405
|
+
* mixpanel.people.clear_charges();
|
|
3406
|
+
*
|
|
3407
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3408
|
+
* @deprecated
|
|
3409
|
+
*/
|
|
3360
3410
|
MixpanelPeople.prototype.clear_charges = function(callback) {
|
|
3361
3411
|
return this.set('$transactions', [], callback);
|
|
3362
3412
|
};
|
|
@@ -4045,6 +4095,7 @@ var NOOP_FUNC = function() {};
|
|
|
4045
4095
|
/** @const */ var PRIMARY_INSTANCE_NAME = 'mixpanel';
|
|
4046
4096
|
/** @const */ var PAYLOAD_TYPE_BASE64 = 'base64';
|
|
4047
4097
|
/** @const */ var PAYLOAD_TYPE_JSON = 'json';
|
|
4098
|
+
/** @const */ var DEVICE_ID_PREFIX = '$device:';
|
|
4048
4099
|
|
|
4049
4100
|
|
|
4050
4101
|
/*
|
|
@@ -4292,7 +4343,7 @@ MixpanelLib.prototype._init = function(token, config, name) {
|
|
|
4292
4343
|
// or the device id if something was already stored
|
|
4293
4344
|
// in the persitence
|
|
4294
4345
|
this.register_once({
|
|
4295
|
-
'distinct_id': uuid,
|
|
4346
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
4296
4347
|
'$device_id': uuid
|
|
4297
4348
|
}, '');
|
|
4298
4349
|
}
|
|
@@ -5218,7 +5269,15 @@ MixpanelLib.prototype.identify = function(
|
|
|
5218
5269
|
// _unset_callback:function A callback to be run if and when the People unset queue is flushed
|
|
5219
5270
|
|
|
5220
5271
|
var previous_distinct_id = this.get_distinct_id();
|
|
5221
|
-
|
|
5272
|
+
if (new_distinct_id && previous_distinct_id !== new_distinct_id) {
|
|
5273
|
+
// we allow the following condition if previous distinct_id is same as new_distinct_id
|
|
5274
|
+
// so that you can force flush people updates for anonymous profiles.
|
|
5275
|
+
if (typeof new_distinct_id === 'string' && new_distinct_id.indexOf(DEVICE_ID_PREFIX) === 0) {
|
|
5276
|
+
this.report_error('distinct_id cannot have $device: prefix');
|
|
5277
|
+
return -1;
|
|
5278
|
+
}
|
|
5279
|
+
this.register({'$user_id': new_distinct_id});
|
|
5280
|
+
}
|
|
5222
5281
|
|
|
5223
5282
|
if (!this.get_property('$device_id')) {
|
|
5224
5283
|
// The persisted distinct id might not actually be a device id at all
|
|
@@ -5259,7 +5318,7 @@ MixpanelLib.prototype.reset = function() {
|
|
|
5259
5318
|
this._flags.identify_called = false;
|
|
5260
5319
|
var uuid = _.UUID();
|
|
5261
5320
|
this.register_once({
|
|
5262
|
-
'distinct_id': uuid,
|
|
5321
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
5263
5322
|
'$device_id': uuid
|
|
5264
5323
|
}, '');
|
|
5265
5324
|
};
|
|
@@ -5384,8 +5443,8 @@ MixpanelLib.prototype.name_tag = function(name_tag) {
|
|
|
5384
5443
|
* // batching or retry mechanisms.
|
|
5385
5444
|
* api_transport: 'XHR'
|
|
5386
5445
|
*
|
|
5387
|
-
* //
|
|
5388
|
-
* batch_requests:
|
|
5446
|
+
* // request-batching/queueing/retry
|
|
5447
|
+
* batch_requests: true,
|
|
5389
5448
|
*
|
|
5390
5449
|
* // maximum number of events/updates to send in a single
|
|
5391
5450
|
* // network request
|
package/dist/mixpanel.globals.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var Config = {
|
|
5
5
|
DEBUG: false,
|
|
6
|
-
LIB_VERSION: '2.
|
|
6
|
+
LIB_VERSION: '2.46.0'
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
@@ -2296,6 +2296,9 @@
|
|
|
2296
2296
|
|
|
2297
2297
|
this.stopped = !this.libConfig['batch_autostart'];
|
|
2298
2298
|
this.consecutiveRemovalFailures = 0;
|
|
2299
|
+
|
|
2300
|
+
// extra client-side dedupe
|
|
2301
|
+
this.itemIdsSentSuccessfully = {};
|
|
2299
2302
|
};
|
|
2300
2303
|
|
|
2301
2304
|
/**
|
|
@@ -2388,7 +2391,34 @@
|
|
|
2388
2391
|
payload = this.beforeSendHook(payload);
|
|
2389
2392
|
}
|
|
2390
2393
|
if (payload) {
|
|
2391
|
-
|
|
2394
|
+
// mp_sent_by_lib_version prop captures which lib version actually
|
|
2395
|
+
// sends each event (regardless of which version originally queued
|
|
2396
|
+
// it for sending)
|
|
2397
|
+
if (payload['event'] && payload['properties']) {
|
|
2398
|
+
payload['properties'] = _.extend(
|
|
2399
|
+
{},
|
|
2400
|
+
payload['properties'],
|
|
2401
|
+
{'mp_sent_by_lib_version': Config.LIB_VERSION}
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
var addPayload = true;
|
|
2405
|
+
var itemId = item['id'];
|
|
2406
|
+
if (itemId) {
|
|
2407
|
+
if ((this.itemIdsSentSuccessfully[itemId] || 0) > 5) {
|
|
2408
|
+
this.reportError('[dupe] item ID sent too many times, not sending', {
|
|
2409
|
+
item: item,
|
|
2410
|
+
batchSize: batch.length,
|
|
2411
|
+
timesSent: this.itemIdsSentSuccessfully[itemId]
|
|
2412
|
+
});
|
|
2413
|
+
addPayload = false;
|
|
2414
|
+
}
|
|
2415
|
+
} else {
|
|
2416
|
+
this.reportError('[dupe] found item with no ID', {item: item});
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
if (addPayload) {
|
|
2420
|
+
dataForRequest.push(payload);
|
|
2421
|
+
}
|
|
2392
2422
|
}
|
|
2393
2423
|
transformedItems[item['id']] = payload;
|
|
2394
2424
|
}, this);
|
|
@@ -2471,6 +2501,24 @@
|
|
|
2471
2501
|
}
|
|
2472
2502
|
}, this)
|
|
2473
2503
|
);
|
|
2504
|
+
|
|
2505
|
+
// client-side dedupe
|
|
2506
|
+
_.each(batch, _.bind(function(item) {
|
|
2507
|
+
var itemId = item['id'];
|
|
2508
|
+
if (itemId) {
|
|
2509
|
+
this.itemIdsSentSuccessfully[itemId] = this.itemIdsSentSuccessfully[itemId] || 0;
|
|
2510
|
+
this.itemIdsSentSuccessfully[itemId]++;
|
|
2511
|
+
if (this.itemIdsSentSuccessfully[itemId] > 5) {
|
|
2512
|
+
this.reportError('[dupe] item ID sent too many times', {
|
|
2513
|
+
item: item,
|
|
2514
|
+
batchSize: batch.length,
|
|
2515
|
+
timesSent: this.itemIdsSentSuccessfully[itemId]
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
} else {
|
|
2519
|
+
this.reportError('[dupe] found item with no ID while removing', {item: item});
|
|
2520
|
+
}
|
|
2521
|
+
}, this));
|
|
2474
2522
|
}
|
|
2475
2523
|
|
|
2476
2524
|
} catch(err) {
|
|
@@ -3316,24 +3364,25 @@
|
|
|
3316
3364
|
});
|
|
3317
3365
|
|
|
3318
3366
|
/*
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3367
|
+
* Record that you have charged the current user a certain amount
|
|
3368
|
+
* of money. Charges recorded with track_charge() will appear in the
|
|
3369
|
+
* Mixpanel revenue report.
|
|
3370
|
+
*
|
|
3371
|
+
* ### Usage:
|
|
3372
|
+
*
|
|
3373
|
+
* // charge a user $50
|
|
3374
|
+
* mixpanel.people.track_charge(50);
|
|
3375
|
+
*
|
|
3376
|
+
* // charge a user $30.50 on the 2nd of january
|
|
3377
|
+
* mixpanel.people.track_charge(30.50, {
|
|
3378
|
+
* '$time': new Date('jan 1 2012')
|
|
3379
|
+
* });
|
|
3380
|
+
*
|
|
3381
|
+
* @param {Number} amount The amount of money charged to the current user
|
|
3382
|
+
* @param {Object} [properties] An associative array of properties associated with the charge
|
|
3383
|
+
* @param {Function} [callback] If provided, the callback will be called when the server responds
|
|
3384
|
+
* @deprecated
|
|
3385
|
+
*/
|
|
3337
3386
|
MixpanelPeople.prototype.track_charge = addOptOutCheckMixpanelPeople(function(amount, properties, callback) {
|
|
3338
3387
|
if (!_.isNumber(amount)) {
|
|
3339
3388
|
amount = parseFloat(amount);
|
|
@@ -3349,15 +3398,16 @@
|
|
|
3349
3398
|
});
|
|
3350
3399
|
|
|
3351
3400
|
/*
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3401
|
+
* Permanently clear all revenue report transactions from the
|
|
3402
|
+
* current user's people analytics profile.
|
|
3403
|
+
*
|
|
3404
|
+
* ### Usage:
|
|
3405
|
+
*
|
|
3406
|
+
* mixpanel.people.clear_charges();
|
|
3407
|
+
*
|
|
3408
|
+
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
3409
|
+
* @deprecated
|
|
3410
|
+
*/
|
|
3361
3411
|
MixpanelPeople.prototype.clear_charges = function(callback) {
|
|
3362
3412
|
return this.set('$transactions', [], callback);
|
|
3363
3413
|
};
|
|
@@ -4046,6 +4096,7 @@
|
|
|
4046
4096
|
/** @const */ var PRIMARY_INSTANCE_NAME = 'mixpanel';
|
|
4047
4097
|
/** @const */ var PAYLOAD_TYPE_BASE64 = 'base64';
|
|
4048
4098
|
/** @const */ var PAYLOAD_TYPE_JSON = 'json';
|
|
4099
|
+
/** @const */ var DEVICE_ID_PREFIX = '$device:';
|
|
4049
4100
|
|
|
4050
4101
|
|
|
4051
4102
|
/*
|
|
@@ -4293,7 +4344,7 @@
|
|
|
4293
4344
|
// or the device id if something was already stored
|
|
4294
4345
|
// in the persitence
|
|
4295
4346
|
this.register_once({
|
|
4296
|
-
'distinct_id': uuid,
|
|
4347
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
4297
4348
|
'$device_id': uuid
|
|
4298
4349
|
}, '');
|
|
4299
4350
|
}
|
|
@@ -5219,7 +5270,15 @@
|
|
|
5219
5270
|
// _unset_callback:function A callback to be run if and when the People unset queue is flushed
|
|
5220
5271
|
|
|
5221
5272
|
var previous_distinct_id = this.get_distinct_id();
|
|
5222
|
-
|
|
5273
|
+
if (new_distinct_id && previous_distinct_id !== new_distinct_id) {
|
|
5274
|
+
// we allow the following condition if previous distinct_id is same as new_distinct_id
|
|
5275
|
+
// so that you can force flush people updates for anonymous profiles.
|
|
5276
|
+
if (typeof new_distinct_id === 'string' && new_distinct_id.indexOf(DEVICE_ID_PREFIX) === 0) {
|
|
5277
|
+
this.report_error('distinct_id cannot have $device: prefix');
|
|
5278
|
+
return -1;
|
|
5279
|
+
}
|
|
5280
|
+
this.register({'$user_id': new_distinct_id});
|
|
5281
|
+
}
|
|
5223
5282
|
|
|
5224
5283
|
if (!this.get_property('$device_id')) {
|
|
5225
5284
|
// The persisted distinct id might not actually be a device id at all
|
|
@@ -5260,7 +5319,7 @@
|
|
|
5260
5319
|
this._flags.identify_called = false;
|
|
5261
5320
|
var uuid = _.UUID();
|
|
5262
5321
|
this.register_once({
|
|
5263
|
-
'distinct_id': uuid,
|
|
5322
|
+
'distinct_id': DEVICE_ID_PREFIX + uuid,
|
|
5264
5323
|
'$device_id': uuid
|
|
5265
5324
|
}, '');
|
|
5266
5325
|
};
|
|
@@ -5385,8 +5444,8 @@
|
|
|
5385
5444
|
* // batching or retry mechanisms.
|
|
5386
5445
|
* api_transport: 'XHR'
|
|
5387
5446
|
*
|
|
5388
|
-
* //
|
|
5389
|
-
* batch_requests:
|
|
5447
|
+
* // request-batching/queueing/retry
|
|
5448
|
+
* batch_requests: true,
|
|
5390
5449
|
*
|
|
5391
5450
|
* // maximum number of events/updates to send in a single
|
|
5392
5451
|
* // network request
|