mixpanel-browser 2.56.0 → 2.57.1
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 +6 -0
- package/LICENSE +1 -15
- package/build.sh +3 -3
- package/dist/mixpanel-core.cjs.js +898 -410
- package/dist/mixpanel-recorder.js +897 -409
- package/dist/mixpanel-recorder.min.js +10 -10
- package/dist/mixpanel-recorder.min.js.map +1 -1
- package/dist/mixpanel-with-async-recorder.cjs.js +898 -410
- package/dist/mixpanel.amd.js +898 -410
- package/dist/mixpanel.cjs.js +898 -410
- package/dist/mixpanel.globals.js +898 -410
- package/dist/mixpanel.min.js +122 -112
- package/dist/mixpanel.module.js +898 -410
- package/dist/mixpanel.umd.js +898 -410
- package/package.json +1 -1
- package/src/config.js +1 -1
- package/src/externs.js +14 -0
- package/src/gdpr-utils.js +2 -1
- package/src/mixpanel-core.js +3 -2
- package/src/promise-polyfill.js +379 -0
- package/src/recorder/index.js +2 -1
- package/src/recorder/session-recording.js +2 -1
- package/src/request-batcher.js +185 -164
- package/src/request-queue.js +200 -147
- package/src/shared-lock.js +104 -98
- package/src/storage/local-storage.js +53 -0
- package/src/storage/wrapper.js +14 -0
- package/src/utils.js +16 -33
- package/src/window.js +20 -0
- package/dist/mixpanel.min.js.map +0 -8
package/src/shared-lock.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Promise } from './promise-polyfill';
|
|
2
|
+
import { console_with_prefix, localStorageSupported, _ } from './utils'; // eslint-disable-line camelcase
|
|
2
3
|
|
|
3
4
|
var logger = console_with_prefix('lock');
|
|
4
5
|
|
|
@@ -29,121 +30,126 @@ var SharedLock = function(key, options) {
|
|
|
29
30
|
this.storage = options.storage || window.localStorage;
|
|
30
31
|
this.pollIntervalMS = options.pollIntervalMS || 100;
|
|
31
32
|
this.timeoutMS = options.timeoutMS || 2000;
|
|
33
|
+
|
|
34
|
+
// dependency-inject promise implementation for testing purposes
|
|
35
|
+
this.promiseImpl = options.promiseImpl || Promise;
|
|
32
36
|
};
|
|
33
37
|
|
|
34
38
|
// pass in a specific pid to test contention scenarios; otherwise
|
|
35
39
|
// it is chosen randomly for each acquisition attempt
|
|
36
|
-
SharedLock.prototype.withLock = function(lockedCB,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
40
|
+
SharedLock.prototype.withLock = function(lockedCB, pid) {
|
|
41
|
+
var Promise = this.promiseImpl;
|
|
42
|
+
return new Promise(_.bind(function (resolve, reject) {
|
|
43
|
+
var i = pid || (new Date().getTime() + '|' + Math.random());
|
|
44
|
+
var startTime = new Date().getTime();
|
|
45
|
+
|
|
46
|
+
var key = this.storageKey;
|
|
47
|
+
var pollIntervalMS = this.pollIntervalMS;
|
|
48
|
+
var timeoutMS = this.timeoutMS;
|
|
49
|
+
var storage = this.storage;
|
|
50
|
+
|
|
51
|
+
var keyX = key + ':X';
|
|
52
|
+
var keyY = key + ':Y';
|
|
53
|
+
var keyZ = key + ':Z';
|
|
54
|
+
|
|
55
|
+
var delay = function(cb) {
|
|
56
|
+
if (new Date().getTime() - startTime > timeoutMS) {
|
|
57
|
+
logger.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
|
|
58
|
+
storage.removeItem(keyZ);
|
|
59
|
+
storage.removeItem(keyY);
|
|
60
|
+
loop();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
setTimeout(function() {
|
|
64
|
+
try {
|
|
65
|
+
cb();
|
|
66
|
+
} catch(err) {
|
|
67
|
+
reject(err);
|
|
68
|
+
}
|
|
69
|
+
}, pollIntervalMS * (Math.random() + 0.1));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
var waitFor = function(predicate, cb) {
|
|
73
|
+
if (predicate()) {
|
|
68
74
|
cb();
|
|
69
|
-
}
|
|
70
|
-
|
|
75
|
+
} else {
|
|
76
|
+
delay(function() {
|
|
77
|
+
waitFor(predicate, cb);
|
|
78
|
+
});
|
|
71
79
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
} else {
|
|
79
|
-
delay(function() {
|
|
80
|
-
waitFor(predicate, cb);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
var getSetY = function() {
|
|
86
|
-
var valY = storage.getItem(keyY);
|
|
87
|
-
if (valY && valY !== i) { // if Y == i then this process already has the lock (useful for test cases)
|
|
88
|
-
return false;
|
|
89
|
-
} else {
|
|
90
|
-
storage.setItem(keyY, i);
|
|
91
|
-
if (storage.getItem(keyY) === i) {
|
|
92
|
-
return true;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
var getSetY = function() {
|
|
83
|
+
var valY = storage.getItem(keyY);
|
|
84
|
+
if (valY && valY !== i) { // if Y == i then this process already has the lock (useful for test cases)
|
|
85
|
+
return false;
|
|
93
86
|
} else {
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
storage.setItem(keyY, i);
|
|
88
|
+
if (storage.getItem(keyY) === i) {
|
|
89
|
+
return true;
|
|
90
|
+
} else {
|
|
91
|
+
if (!localStorageSupported(storage, true)) {
|
|
92
|
+
reject(new Error('localStorage support dropped while acquiring lock'));
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
96
95
|
}
|
|
97
|
-
return false;
|
|
98
96
|
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
var loop = function() {
|
|
103
|
-
storage.setItem(keyX, i);
|
|
97
|
+
};
|
|
104
98
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
criticalSection();
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
99
|
+
var loop = function() {
|
|
100
|
+
storage.setItem(keyX, i);
|
|
110
101
|
|
|
111
|
-
|
|
112
|
-
if (storage.getItem(
|
|
113
|
-
|
|
102
|
+
waitFor(getSetY, function() {
|
|
103
|
+
if (storage.getItem(keyX) === i) {
|
|
104
|
+
criticalSection();
|
|
114
105
|
return;
|
|
115
106
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
|
|
108
|
+
delay(function() {
|
|
109
|
+
if (storage.getItem(keyY) !== i) {
|
|
110
|
+
loop();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
waitFor(function() {
|
|
114
|
+
return !storage.getItem(keyZ);
|
|
115
|
+
}, criticalSection);
|
|
116
|
+
});
|
|
119
117
|
});
|
|
120
|
-
}
|
|
121
|
-
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
var criticalSection = function() {
|
|
121
|
+
storage.setItem(keyZ, '1');
|
|
122
|
+
var removeLock = function () {
|
|
123
|
+
storage.removeItem(keyZ);
|
|
124
|
+
if (storage.getItem(keyY) === i) {
|
|
125
|
+
storage.removeItem(keyY);
|
|
126
|
+
}
|
|
127
|
+
if (storage.getItem(keyX) === i) {
|
|
128
|
+
storage.removeItem(keyX);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
lockedCB()
|
|
133
|
+
.then(function (ret) {
|
|
134
|
+
removeLock();
|
|
135
|
+
resolve(ret);
|
|
136
|
+
})
|
|
137
|
+
.catch(function (err) {
|
|
138
|
+
removeLock();
|
|
139
|
+
reject(err);
|
|
140
|
+
});
|
|
141
|
+
};
|
|
122
142
|
|
|
123
|
-
var criticalSection = function() {
|
|
124
|
-
storage.setItem(keyZ, '1');
|
|
125
143
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
storage.removeItem(keyY);
|
|
131
|
-
}
|
|
132
|
-
if (storage.getItem(keyX) === i) {
|
|
133
|
-
storage.removeItem(keyX);
|
|
144
|
+
if (localStorageSupported(storage, true)) {
|
|
145
|
+
loop();
|
|
146
|
+
} else {
|
|
147
|
+
throw new Error('localStorage support check failed');
|
|
134
148
|
}
|
|
149
|
+
} catch(err) {
|
|
150
|
+
reject(err);
|
|
135
151
|
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
if (localStorageSupported(storage, true)) {
|
|
140
|
-
loop();
|
|
141
|
-
} else {
|
|
142
|
-
throw new Error('localStorage support check failed');
|
|
143
|
-
}
|
|
144
|
-
} catch(err) {
|
|
145
|
-
reportError(err);
|
|
146
|
-
}
|
|
152
|
+
}, this));
|
|
147
153
|
};
|
|
148
154
|
|
|
149
155
|
export { SharedLock };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Promise } from '../promise-polyfill';
|
|
2
|
+
import { _ } from '../utils'; // eslint-disable-line camelcase
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('./wrapper').StorageWrapper}
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @type {StorageWrapper}
|
|
10
|
+
*/
|
|
11
|
+
var LocalStorageWrapper = function (storageOverride) {
|
|
12
|
+
this.storage = storageOverride || localStorage;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
LocalStorageWrapper.prototype.init = function () {
|
|
16
|
+
return Promise.resolve();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
LocalStorageWrapper.prototype.setItem = function (key, value) {
|
|
20
|
+
return new Promise(_.bind(function (resolve, reject) {
|
|
21
|
+
try {
|
|
22
|
+
this.storage.setItem(key, value);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
reject(e);
|
|
25
|
+
}
|
|
26
|
+
resolve();
|
|
27
|
+
}, this));
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
LocalStorageWrapper.prototype.getItem = function (key) {
|
|
31
|
+
return new Promise(_.bind(function (resolve, reject) {
|
|
32
|
+
var item;
|
|
33
|
+
try {
|
|
34
|
+
item = this.storage.getItem(key);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
reject(e);
|
|
37
|
+
}
|
|
38
|
+
resolve(item);
|
|
39
|
+
}, this));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
LocalStorageWrapper.prototype.removeItem = function (key) {
|
|
43
|
+
return new Promise(_.bind(function (resolve, reject) {
|
|
44
|
+
try {
|
|
45
|
+
this.storage.removeItem(key);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
reject(e);
|
|
48
|
+
}
|
|
49
|
+
resolve();
|
|
50
|
+
}, this));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export { LocalStorageWrapper };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage abstraction layer to support sync/async browser storage mechanisms.
|
|
3
|
+
* This file only exists for the jsdoc type definition.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} StorageWrapper
|
|
8
|
+
* @property {function():Promise<void>} init - Initializes the wrapper, async storage like IDB needs to create a table and upgrade if needed.
|
|
9
|
+
* @property {function(string, string):Promise<void>} setItem - Sets an item in storage.
|
|
10
|
+
* @property {function(string):Promise<string>} getItem - Retrieves an item from storage.
|
|
11
|
+
* @property {function(string, string):Promise<void>} removeItem - Removes an item from storage.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export { };
|
package/src/utils.js
CHANGED
|
@@ -1,24 +1,7 @@
|
|
|
1
1
|
/* eslint camelcase: "off", eqeqeq: "off" */
|
|
2
2
|
import Config from './config';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var win;
|
|
6
|
-
if (typeof(window) === 'undefined') {
|
|
7
|
-
var loc = {
|
|
8
|
-
hostname: ''
|
|
9
|
-
};
|
|
10
|
-
win = {
|
|
11
|
-
navigator: { userAgent: '', onLine: true },
|
|
12
|
-
document: {
|
|
13
|
-
location: loc,
|
|
14
|
-
referrer: ''
|
|
15
|
-
},
|
|
16
|
-
screen: { width: 0, height: 0 },
|
|
17
|
-
location: loc
|
|
18
|
-
};
|
|
19
|
-
} else {
|
|
20
|
-
win = window;
|
|
21
|
-
}
|
|
3
|
+
import { NpoPromise } from './promise-polyfill';
|
|
4
|
+
import { window } from './window';
|
|
22
5
|
|
|
23
6
|
// Maximum allowed session recording length
|
|
24
7
|
var MAX_RECORDING_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
@@ -36,11 +19,11 @@ var ArrayProto = Array.prototype,
|
|
|
36
19
|
slice = ArrayProto.slice,
|
|
37
20
|
toString = ObjProto.toString,
|
|
38
21
|
hasOwnProperty = ObjProto.hasOwnProperty,
|
|
39
|
-
windowConsole =
|
|
40
|
-
navigator =
|
|
41
|
-
document =
|
|
42
|
-
windowOpera =
|
|
43
|
-
screen =
|
|
22
|
+
windowConsole = window.console,
|
|
23
|
+
navigator = window.navigator,
|
|
24
|
+
document = window.document,
|
|
25
|
+
windowOpera = window.opera,
|
|
26
|
+
screen = window.screen,
|
|
44
27
|
userAgent = navigator.userAgent;
|
|
45
28
|
|
|
46
29
|
var nativeBind = FuncProto.bind,
|
|
@@ -839,8 +822,8 @@ _.UUID = (function() {
|
|
|
839
822
|
var T = function() {
|
|
840
823
|
var time = 1 * new Date(); // cross-browser version of Date.now()
|
|
841
824
|
var ticks;
|
|
842
|
-
if (
|
|
843
|
-
ticks =
|
|
825
|
+
if (window.performance && window.performance.now) {
|
|
826
|
+
ticks = window.performance.now();
|
|
844
827
|
} else {
|
|
845
828
|
// fall back to busy loop
|
|
846
829
|
ticks = 0;
|
|
@@ -1626,7 +1609,7 @@ _.info = {
|
|
|
1626
1609
|
},
|
|
1627
1610
|
|
|
1628
1611
|
currentUrl: function() {
|
|
1629
|
-
return
|
|
1612
|
+
return window.location.href;
|
|
1630
1613
|
},
|
|
1631
1614
|
|
|
1632
1615
|
properties: function(extra_props) {
|
|
@@ -1663,10 +1646,10 @@ _.info = {
|
|
|
1663
1646
|
mpPageViewProperties: function() {
|
|
1664
1647
|
return _.strip_empty_properties({
|
|
1665
1648
|
'current_page_title': document.title,
|
|
1666
|
-
'current_domain':
|
|
1667
|
-
'current_url_path':
|
|
1668
|
-
'current_url_protocol':
|
|
1669
|
-
'current_url_search':
|
|
1649
|
+
'current_domain': window.location.hostname,
|
|
1650
|
+
'current_url_path': window.location.pathname,
|
|
1651
|
+
'current_url_protocol': window.location.protocol,
|
|
1652
|
+
'current_url_search': window.location.search
|
|
1670
1653
|
});
|
|
1671
1654
|
}
|
|
1672
1655
|
};
|
|
@@ -1709,7 +1692,7 @@ var extract_domain = function(hostname) {
|
|
|
1709
1692
|
* @returns {boolean}
|
|
1710
1693
|
*/
|
|
1711
1694
|
var isOnline = function() {
|
|
1712
|
-
var onLine =
|
|
1695
|
+
var onLine = window.navigator['onLine'];
|
|
1713
1696
|
return _.isUndefined(onLine) || onLine;
|
|
1714
1697
|
};
|
|
1715
1698
|
|
|
@@ -1733,6 +1716,7 @@ _['info']['device'] = _.info.device;
|
|
|
1733
1716
|
_['info']['browser'] = _.info.browser;
|
|
1734
1717
|
_['info']['browserVersion'] = _.info.browserVersion;
|
|
1735
1718
|
_['info']['properties'] = _.info.properties;
|
|
1719
|
+
_['NPO'] = NpoPromise;
|
|
1736
1720
|
|
|
1737
1721
|
export {
|
|
1738
1722
|
_,
|
|
@@ -1750,5 +1734,4 @@ export {
|
|
|
1750
1734
|
navigator,
|
|
1751
1735
|
slice,
|
|
1752
1736
|
userAgent,
|
|
1753
|
-
win as window
|
|
1754
1737
|
};
|
package/src/window.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
|
|
2
|
+
var win;
|
|
3
|
+
if (typeof(window) === 'undefined') {
|
|
4
|
+
var loc = {
|
|
5
|
+
hostname: ''
|
|
6
|
+
};
|
|
7
|
+
win = {
|
|
8
|
+
navigator: { userAgent: '', onLine: true },
|
|
9
|
+
document: {
|
|
10
|
+
location: loc,
|
|
11
|
+
referrer: ''
|
|
12
|
+
},
|
|
13
|
+
screen: { width: 0, height: 0 },
|
|
14
|
+
location: loc
|
|
15
|
+
};
|
|
16
|
+
} else {
|
|
17
|
+
win = window;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { win as window };
|