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.
@@ -1,4 +1,5 @@
1
- import { console_with_prefix, localStorageSupported } from './utils'; // eslint-disable-line camelcase
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, errorCB, pid) {
37
- if (!pid && typeof errorCB !== 'function') {
38
- pid = errorCB;
39
- errorCB = null;
40
- }
41
-
42
- var i = pid || (new Date().getTime() + '|' + Math.random());
43
- var startTime = new Date().getTime();
44
-
45
- var key = this.storageKey;
46
- var pollIntervalMS = this.pollIntervalMS;
47
- var timeoutMS = this.timeoutMS;
48
- var storage = this.storage;
49
-
50
- var keyX = key + ':X';
51
- var keyY = key + ':Y';
52
- var keyZ = key + ':Z';
53
-
54
- var reportError = function(err) {
55
- errorCB && errorCB(err);
56
- };
57
-
58
- var delay = function(cb) {
59
- if (new Date().getTime() - startTime > timeoutMS) {
60
- logger.error('Timeout waiting for mutex on ' + key + '; clearing lock. [' + i + ']');
61
- storage.removeItem(keyZ);
62
- storage.removeItem(keyY);
63
- loop();
64
- return;
65
- }
66
- setTimeout(function() {
67
- try {
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
- } catch(err) {
70
- reportError(err);
75
+ } else {
76
+ delay(function() {
77
+ waitFor(predicate, cb);
78
+ });
71
79
  }
72
- }, pollIntervalMS * (Math.random() + 0.1));
73
- };
74
-
75
- var waitFor = function(predicate, cb) {
76
- if (predicate()) {
77
- cb();
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
- if (!localStorageSupported(storage, true)) {
95
- throw new Error('localStorage support dropped while acquiring lock');
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
- waitFor(getSetY, function() {
106
- if (storage.getItem(keyX) === i) {
107
- criticalSection();
108
- return;
109
- }
99
+ var loop = function() {
100
+ storage.setItem(keyX, i);
110
101
 
111
- delay(function() {
112
- if (storage.getItem(keyY) !== i) {
113
- loop();
102
+ waitFor(getSetY, function() {
103
+ if (storage.getItem(keyX) === i) {
104
+ criticalSection();
114
105
  return;
115
106
  }
116
- waitFor(function() {
117
- return !storage.getItem(keyZ);
118
- }, criticalSection);
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
- lockedCB();
127
- } finally {
128
- storage.removeItem(keyZ);
129
- if (storage.getItem(keyY) === i) {
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
- // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
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 = win.console,
40
- navigator = win.navigator,
41
- document = win.document,
42
- windowOpera = win.opera,
43
- screen = win.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 (win.performance && win.performance.now) {
843
- ticks = win.performance.now();
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 win.location.href;
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': win.location.hostname,
1667
- 'current_url_path': win.location.pathname,
1668
- 'current_url_protocol': win.location.protocol,
1669
- 'current_url_search': win.location.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 = win.navigator['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 };