mixpanel-browser 2.61.2 → 2.63.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixpanel-browser",
3
- "version": "2.61.2",
3
+ "version": "2.63.0",
4
4
  "description": "The official Mixpanel JavaScript browser client library",
5
5
  "main": "dist/mixpanel.cjs.js",
6
6
  "module": "dist/mixpanel.module.js",
@@ -33,7 +33,11 @@
33
33
  },
34
34
  "homepage": "https://github.com/mixpanel/mixpanel-js",
35
35
  "devDependencies": {
36
+ "@ampproject/rollup-plugin-closure-compiler": "0.27.0",
37
+ "@rollup/plugin-alias": "5.1.1",
36
38
  "@rollup/plugin-node-resolve": "15.2.3",
39
+ "@rollup/plugin-swc": "0.4.0",
40
+ "@swc/core": "1.11.7",
37
41
  "babel": "6.5.2",
38
42
  "babel-core": "6.7.2",
39
43
  "babel-preset-es2015": "6.6.0",
@@ -54,13 +58,13 @@
54
58
  "morgan": "1.9.1",
55
59
  "rdme": "7.5.0",
56
60
  "request": "2.88.0",
57
- "rollup": "2.79.1",
58
- "rollup-plugin-esbuild": "4.10.3",
61
+ "rollup": "4.34.9",
62
+ "rollup-plugin-esbuild": "6.2.1",
59
63
  "sinon": "8.1.1",
60
64
  "sinon-chai": "3.5.0",
61
65
  "webpack": "1.12.2"
62
66
  },
63
67
  "dependencies": {
64
- "rrweb": "2.0.0-alpha.13"
68
+ "rrweb": "2.0.0-alpha.18"
65
69
  }
66
70
  }
@@ -0,0 +1,223 @@
1
+ import nodeResolve from '@rollup/plugin-node-resolve';
2
+ import swc from '@rollup/plugin-swc';
3
+ import esbuild from 'rollup-plugin-esbuild';
4
+ import alias from '@rollup/plugin-alias';
5
+ import closureCompiler from '@ampproject/rollup-plugin-closure-compiler';
6
+
7
+ const COMPILED_RRWEB_PATH = 'build/rrweb-compiled.js';
8
+
9
+ const aliasRrweb = () => alias({
10
+ entries: [
11
+ { find: 'rrweb', replacement: COMPILED_RRWEB_PATH },
12
+ ]
13
+ });
14
+
15
+ const COMMON_CLOSURE_FLAGS = {
16
+ compilation_level: 'ADVANCED_OPTIMIZATIONS',
17
+ language_in: 'ECMASCRIPT5',
18
+ externs: ['src/externs.js'],
19
+ };
20
+
21
+ const MINIFY = process.env.MINIFY || process.env.FULL;
22
+
23
+ // Main builds used to develop / iterate quickly
24
+ const MAIN_BUILDS = [
25
+ // compile rrweb first to es5 with swc, we'll replace the import later on
26
+ {
27
+ 'input': 'rrweb',
28
+ 'output': [
29
+ {
30
+ file: COMPILED_RRWEB_PATH,
31
+ }
32
+ ],
33
+ plugins: [nodeResolve({browser: true}), swc({swc: {jsc: {target: 'es5'}}})]
34
+ },
35
+
36
+ // IIFE recorder bundle that is loaded asynchronously
37
+ // rrweb uses esbuild to minify, so do that here as well
38
+ {
39
+ input: 'src/recorder/index.js',
40
+ output: [
41
+ {
42
+ file: 'build/mixpanel-recorder.js',
43
+ name: 'mixpanel_recorder',
44
+ format: 'iife',
45
+ },
46
+ ...(MINIFY
47
+ ? [
48
+ {
49
+ file: 'build/mixpanel-recorder.min.js',
50
+ name: 'mixpanel_recorder',
51
+ format: 'iife',
52
+ plugins: [esbuild({target: 'es5', minify: true, sourceMap: true})],
53
+ sourcemap: true,
54
+ },
55
+ ]
56
+ : []),
57
+ ],
58
+ plugins: [aliasRrweb()],
59
+ },
60
+
61
+ // IIFE main mixpanel build
62
+ {
63
+ input: 'src/loaders/loader-globals.js',
64
+ output: [
65
+ {
66
+ file: 'build/mixpanel.globals.js',
67
+ name: 'mixpanel',
68
+ format: 'iife',
69
+ },
70
+ ...(MINIFY
71
+ ? [
72
+ {
73
+ file: 'build/mixpanel.min.js',
74
+ format: 'iife',
75
+ plugins: [closureCompiler(COMMON_CLOSURE_FLAGS)],
76
+ },
77
+ ]
78
+ : []),
79
+ ],
80
+ plugins: [
81
+ nodeResolve({
82
+ browser: true,
83
+ main: true,
84
+ jsnext: true,
85
+ })
86
+ ]
87
+ },
88
+ ]
89
+
90
+ const ALL_BUILDS = [
91
+ ...MAIN_BUILDS,
92
+ // Minified snippets for loading mixpanel
93
+ {
94
+ input: 'src/loaders/mixpanel-jslib-snippet.js',
95
+ output: [
96
+ {
97
+ file: 'build/mixpanel-jslib-snippet.min.js',
98
+ plugins: [closureCompiler(COMMON_CLOSURE_FLAGS)]
99
+ },
100
+ {
101
+ file: 'build/mixpanel-jslib-snippet.min.test.js',
102
+ plugins: [closureCompiler({...COMMON_CLOSURE_FLAGS, define: 'MIXPANEL_LIB_URL="../build/mixpanel.min.js"'})],
103
+ }
104
+ ],
105
+ },
106
+
107
+ // IIFE mixpanel snippet loader
108
+ {
109
+ input: 'src/loaders/mixpanel-js-wrapper.js',
110
+ output: [
111
+ {
112
+ file: 'build/mixpanel-js-wrapper.js',
113
+ },
114
+ {
115
+ file: 'build/mixpanel-js-wrapper.min.js',
116
+ plugins: [closureCompiler(COMMON_CLOSURE_FLAGS)],
117
+ }
118
+ ],
119
+ },
120
+
121
+ // IIFE mixpanel core with bundled recorder
122
+ {
123
+ input: 'src/loaders/loader-globals-with-recorder.js',
124
+ output: [
125
+ {
126
+ file: 'build/mixpanel-with-recorder.js',
127
+ name: 'mixpanel',
128
+ format: 'iife',
129
+ },
130
+ {
131
+ file: 'build/mixpanel-with-recorder.min.js',
132
+ name: 'mixpanel',
133
+ format: 'iife',
134
+ plugins: [esbuild({target: 'es5', minify: true, sourceMap: true})],
135
+ },
136
+ ],
137
+ plugins: [
138
+ aliasRrweb(),
139
+ nodeResolve({
140
+ browser: true,
141
+ main: true,
142
+ jsnext: true,
143
+ })
144
+ ],
145
+ },
146
+
147
+
148
+ // Modules builds that are bundled with the recorder
149
+ {
150
+ input: 'src/loaders/loader-module.js',
151
+ output: [
152
+ {
153
+ file: 'build/mixpanel.cjs.js',
154
+ name: 'mixpanel',
155
+ format: 'cjs',
156
+ },
157
+ {
158
+ file: 'build/mixpanel.amd.js',
159
+ name: 'mixpanel',
160
+ format: 'amd',
161
+ },
162
+ {
163
+ file: 'build/mixpanel.umd.js',
164
+ name: 'mixpanel',
165
+ format: 'umd',
166
+ },
167
+ {
168
+ file: 'build/mixpanel.module.js',
169
+ name: 'mixpanel',
170
+ format: 'es',
171
+ },
172
+ ],
173
+ plugins: [
174
+ aliasRrweb(),
175
+ nodeResolve({
176
+ browser: true,
177
+ main: true,
178
+ jsnext: true,
179
+ })
180
+ ],
181
+ },
182
+
183
+
184
+ // Alternative CJS builds without recorder
185
+ {
186
+ input: 'src/loaders/loader-module-core.js',
187
+ output: [
188
+ {
189
+ file: 'build/mixpanel-core.cjs.js',
190
+ name: 'mixpanel',
191
+ format: 'cjs',
192
+ },
193
+ ],
194
+ plugins: [
195
+ aliasRrweb(),
196
+ nodeResolve({
197
+ browser: true,
198
+ main: true,
199
+ jsnext: true,
200
+ })
201
+ ],
202
+ },
203
+ {
204
+ input: 'src/loaders/loader-module-with-async-recorder.js',
205
+ output: [
206
+ {
207
+ file: 'build/mixpanel-with-async-recorder.cjs.js',
208
+ name: 'mixpanel',
209
+ format: 'cjs',
210
+ },
211
+ ],
212
+ plugins: [
213
+ aliasRrweb(),
214
+ nodeResolve({
215
+ browser: true,
216
+ main: true,
217
+ jsnext: true,
218
+ })
219
+ ],
220
+ }
221
+ ];
222
+
223
+ export default process.env.FULL ? ALL_BUILDS : MAIN_BUILDS;
package/src/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var Config = {
2
2
  DEBUG: false,
3
- LIB_VERSION: '2.61.2'
3
+ LIB_VERSION: '2.63.0'
4
4
  };
5
5
 
6
6
  export default Config;
@@ -0,0 +1,7 @@
1
+ /* eslint camelcase: "off" */
2
+ import '../recorder';
3
+
4
+ import { init_from_snippet } from '../mixpanel-core';
5
+ import { loadNoop } from './bundle-loaders';
6
+
7
+ init_from_snippet(loadNoop);
@@ -1,6 +1,6 @@
1
1
  /* eslint camelcase: "off" */
2
2
  import Config from './config';
3
- import { MAX_RECORDING_MS, _, console, userAgent, document, navigator, slice, NOOP_FUNC } from './utils';
3
+ import { MAX_RECORDING_MS, _, console, userAgent, document, navigator, slice, NOOP_FUNC, JSONStringify } from './utils';
4
4
  import { isRecordingExpired } from './recorder/utils';
5
5
  import { window } from './window';
6
6
  import { Autocapture } from './autocapture';
@@ -932,7 +932,7 @@ MixpanelLib.prototype.disable = function(events) {
932
932
  };
933
933
 
934
934
  MixpanelLib.prototype._encode_data_for_request = function(data) {
935
- var encoded_data = _.JSONEncode(data);
935
+ var encoded_data = JSONStringify(data);
936
936
  if (this.get_config('api_payload_format') === PAYLOAD_TYPE_BASE64) {
937
937
  encoded_data = _.base64Encode(encoded_data);
938
938
  }
@@ -9,7 +9,7 @@ import {
9
9
  REMOVE_ACTION,
10
10
  UNION_ACTION
11
11
  } from './api-actions';
12
- import { _, console } from './utils';
12
+ import { _, console, JSONStringify } from './utils';
13
13
 
14
14
  /*
15
15
  * Constants
@@ -125,7 +125,7 @@ MixpanelPersistence.prototype.save = function() {
125
125
 
126
126
  this.storage.set(
127
127
  this.name,
128
- _.JSONEncode(this['props']),
128
+ JSONStringify(this['props']),
129
129
  this.expire_days,
130
130
  this.cross_subdomain,
131
131
  this.secure,
@@ -1,5 +1,5 @@
1
1
  import { window } from '../window';
2
- import { IncrementalSource, EventType } from '@rrweb/types';
2
+ import { IncrementalSource, EventType } from 'rrweb';
3
3
  import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, NOOP_FUNC, _, localStorageSupported} from '../utils'; // eslint-disable-line camelcase
4
4
  import { IDBStorageWrapper, RECORDING_EVENTS_STORE_NAME } from '../storage/indexed-db';
5
5
  import { addOptOutCheckMixpanelLib } from '../gdpr-utils';
@@ -187,6 +187,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
187
187
  this.idleTimeoutId = setTimeout(this._onIdleTimeout, idleTimeoutMs);
188
188
  this.idleExpires = new Date().getTime() + idleTimeoutMs;
189
189
  }.bind(this);
190
+ resetIdleTimeout();
190
191
 
191
192
  var blockSelector = this.getConfig('record_block_selector');
192
193
  if (blockSelector === '' || blockSelector === null) {
@@ -196,6 +197,10 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
196
197
  try {
197
198
  this._stopRecording = this._rrwebRecord({
198
199
  'emit': function (ev) {
200
+ if (this.idleExpires && this.idleExpires < ev.timestamp) {
201
+ this._onIdleTimeout();
202
+ return;
203
+ }
199
204
  if (isUserEvent(ev)) {
200
205
  if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
201
206
  // start flushing again after user activity
@@ -232,8 +237,6 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
232
237
  return;
233
238
  }
234
239
 
235
- resetIdleTimeout();
236
-
237
240
  var maxTimeoutMs = this.maxExpires - new Date().getTime();
238
241
  this.maxTimeoutId = setTimeout(this._onMaxLengthReached.bind(this), maxTimeoutMs);
239
242
  };
@@ -412,7 +415,7 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
412
415
  'replay_start_url': this.replayStartUrl,
413
416
  'seq': this.seqNo
414
417
  };
415
- var eventsJson = _.JSONEncode(data);
418
+ var eventsJson = JSON.stringify(data);
416
419
 
417
420
  // send ID management props if they exist
418
421
  var deviceId = this._mixpanel.get_property('$device_id');
@@ -1,11 +1,12 @@
1
1
  import { Promise } from '../promise-polyfill';
2
2
  import { _, JSONParse, JSONStringify } from '../utils'; // eslint-disable-line camelcase
3
+ import { window } from '../window';
3
4
 
4
5
  /**
5
6
  * @type {import('./wrapper').StorageWrapper}
6
7
  */
7
8
  var LocalStorageWrapper = function (storageOverride) {
8
- this.storage = storageOverride || localStorage;
9
+ this.storage = storageOverride || window.localStorage;
9
10
  };
10
11
 
11
12
  LocalStorageWrapper.prototype.init = function () {
package/src/utils.js CHANGED
@@ -839,71 +839,27 @@ _.utf8Encode = function(string) {
839
839
  return utftext;
840
840
  };
841
841
 
842
- _.UUID = (function() {
843
-
844
- // Time-based entropy
845
- var T = function() {
846
- var time = 1 * new Date(); // cross-browser version of Date.now()
847
- var ticks;
848
- if (window.performance && window.performance.now) {
849
- ticks = window.performance.now();
850
- } else {
851
- // fall back to busy loop
852
- ticks = 0;
853
-
854
- // this while loop figures how many browser ticks go by
855
- // before 1*new Date() returns a new number, ie the amount
856
- // of ticks that go by per millisecond
857
- while (time == 1 * new Date()) {
858
- ticks++;
859
- }
860
- }
861
- return time.toString(16) + Math.floor(ticks).toString(16);
862
- };
863
-
864
- // Math.Random entropy
865
- var R = function() {
866
- return Math.random().toString(16).replace('.', '');
867
- };
868
-
869
- // User agent entropy
870
- // This function takes the user agent string, and then xors
871
- // together each sequence of 8 bytes. This produces a final
872
- // sequence of 8 bytes which it returns as hex.
873
- var UA = function() {
874
- var ua = userAgent,
875
- i, ch, buffer = [],
876
- ret = 0;
877
-
878
- function xor(result, byte_array) {
879
- var j, tmp = 0;
880
- for (j = 0; j < byte_array.length; j++) {
881
- tmp |= (buffer[j] << j * 8);
882
- }
883
- return result ^ tmp;
884
- }
885
-
886
- for (i = 0; i < ua.length; i++) {
887
- ch = ua.charCodeAt(i);
888
- buffer.unshift(ch & 0xFF);
889
- if (buffer.length >= 4) {
890
- ret = xor(ret, buffer);
891
- buffer = [];
892
- }
893
- }
894
-
895
- if (buffer.length > 0) {
896
- ret = xor(ret, buffer);
842
+ _.UUID = function() {
843
+ try {
844
+ // use native Crypto API when available
845
+ return window['crypto']['randomUUID']();
846
+ } catch (err) {
847
+ // fall back to generating our own UUID
848
+ // based on https://gist.github.com/scwood/3bff42cc005cc20ab7ec98f0d8e1d59d
849
+ var uuid = new Array(36);
850
+ for (var i = 0; i < 36; i++) {
851
+ uuid[i] = Math.floor(Math.random() * 16);
897
852
  }
898
-
899
- return ret.toString(16);
900
- };
901
-
902
- return function() {
903
- var se = (screen.height * screen.width).toString(16);
904
- return (T() + '-' + R() + '-' + UA() + '-' + se + '-' + T());
905
- };
906
- })();
853
+ uuid[14] = 4; // set bits 12-15 of time-high-and-version to 0100
854
+ uuid[19] = uuid[19] &= ~(1 << 2); // set bit 6 of clock-seq-and-reserved to zero
855
+ uuid[19] = uuid[19] |= (1 << 3); // set bit 7 of clock-seq-and-reserved to one
856
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
857
+
858
+ return _.map(uuid, function(x) {
859
+ return x.toString(16);
860
+ }).join('');
861
+ }
862
+ };
907
863
 
908
864
  // _.isBlockedUA()
909
865
  // This is to block various web spiders from executing our JS and
package/src/window.js CHANGED
@@ -5,6 +5,7 @@ if (typeof(window) === 'undefined') {
5
5
  hostname: ''
6
6
  };
7
7
  win = {
8
+ crypto: {randomUUID: function() {throw Error('unsupported');}},
8
9
  navigator: { userAgent: '', onLine: true },
9
10
  document: {
10
11
  createElement: function() { return {}; },
package/rollup.config.js DELETED
@@ -1,11 +0,0 @@
1
- import nodeResolve from '@rollup/plugin-node-resolve';
2
-
3
- export default {
4
- plugins: [
5
- nodeResolve({
6
- browser: true,
7
- main: true,
8
- jsnext: true,
9
- })
10
- ]
11
- };
@@ -1,20 +0,0 @@
1
- import esbuild from 'rollup-plugin-esbuild';
2
- import { nodeResolve } from '@rollup/plugin-node-resolve';
3
-
4
- export default {
5
- input: 'index.js',
6
- output: [
7
- {
8
- file: 'build/mixpanel-recorder.js',
9
- format: 'esm'
10
- },
11
- {
12
- file: 'build/mixpanel-recorder.min.js',
13
- format: 'esm',
14
- name: 'version',
15
- plugins: [esbuild({minify: true, sourceMap: true})],
16
- sourcemap: true,
17
- }
18
- ],
19
- plugins: [nodeResolve({browser: true})],
20
- };