mixpanel-browser 2.56.0 → 2.58.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.56.0",
3
+ "version": "2.58.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",
package/src/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var Config = {
2
2
  DEBUG: false,
3
- LIB_VERSION: '2.56.0'
3
+ LIB_VERSION: '2.58.0'
4
4
  };
5
5
 
6
6
  export default Config;
package/src/externs.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @fileoverview Externs for Promise polyfill so that closure compiler does not try to rename methods.
3
+ * https://developers.google.com/closure/compiler/docs/externs-and-exports
4
+ * @externs
5
+ */
6
+ var Promise = {};
7
+
8
+ Promise.resolve = function() {};
9
+ Promise.reject = function() {};
10
+ Promise.race = function() {};
11
+ Promise.all = function() {};
12
+
13
+ Promise.prototype.then = function() {};
14
+ Promise.prototype.catch = function() {};
package/src/gdpr-utils.js CHANGED
@@ -11,7 +11,8 @@
11
11
  * These functions are used internally by the SDK and are not intended to be publicly exposed.
12
12
  */
13
13
 
14
- import { _, console, window } from './utils';
14
+ import { _, console } from './utils';
15
+ import { window } from './window';
15
16
 
16
17
  /**
17
18
  * A function used to track a Mixpanel event (e.g. MixpanelLib.track)
@@ -1,6 +1,7 @@
1
1
  /* eslint camelcase: "off" */
2
2
  import Config from './config';
3
- import { MAX_RECORDING_MS, _, console, userAgent, window, document, navigator, slice } from './utils';
3
+ import { MAX_RECORDING_MS, _, console, userAgent, document, navigator, slice } from './utils';
4
+ import { window } from './window';
4
5
  import { FormTracker, LinkTracker } from './dom-trackers';
5
6
  import { RequestBatcher } from './request-batcher';
6
7
  import { MixpanelGroup } from './mixpanel-group';
@@ -146,6 +147,7 @@ var DEFAULT_CONFIG = {
146
147
  'hooks': {},
147
148
  'record_block_class': new RegExp('^(mp-block|fs-exclude|amp-block|rr-block|ph-no-capture)$'),
148
149
  'record_block_selector': 'img, video',
150
+ 'record_canvas': false,
149
151
  'record_collect_fonts': false,
150
152
  'record_idle_timeout_ms': 30 * 60 * 1000, // 30 minutes
151
153
  'record_mask_text_class': new RegExp('^(mp-mask|fs-mask|amp-mask|rr-mask|ph-mask)$'),
@@ -923,7 +925,7 @@ MixpanelLib.prototype._track_or_batch = function(options, callback) {
923
925
  }, this);
924
926
 
925
927
  if (this._batch_requests && !should_send_immediately) {
926
- batcher.enqueue(truncated_data, function(succeeded) {
928
+ batcher.enqueue(truncated_data).then(function(succeeded) {
927
929
  if (succeeded) {
928
930
  callback(1, truncated_data);
929
931
  } else {
@@ -0,0 +1,379 @@
1
+ import { window } from './window';
2
+ /**
3
+ * Promise polyfill sourced from https://github.com/getify/native-promise-only.
4
+ * Modified to
5
+ * - remove UMD wrapper and export as an object, so that we don't globally polyfill Promise.
6
+ * - rename access notation for dynamically referenced props to avoid minification, e.g. this.__NPO__ -> this['__NPO__']
7
+ */
8
+
9
+ /*! Native Promise Only
10
+ v0.8.1 (c) Kyle Simpson
11
+ MIT License: http://getify.mit-license.org
12
+ */
13
+
14
+ /*jshint validthis:true */
15
+ 'use strict';
16
+
17
+ var setImmediate = window['setImmediate'];
18
+ var builtInProp, cycle, schedulingQueue,
19
+ ToString = Object.prototype.toString,
20
+ timer = (typeof setImmediate !== 'undefined') ?
21
+ function timer(fn) { return setImmediate(fn); } :
22
+ setTimeout;
23
+
24
+ // dammit, IE8.
25
+ try {
26
+ Object.defineProperty({},'x',{});
27
+ builtInProp = function builtInProp(obj,name,val,config) {
28
+ return Object.defineProperty(obj,name,{
29
+ value: val,
30
+ writable: true,
31
+ configurable: config !== false
32
+ });
33
+ };
34
+ }
35
+ catch (err) {
36
+ builtInProp = function builtInProp(obj,name,val) {
37
+ obj[name] = val;
38
+ return obj;
39
+ };
40
+ }
41
+
42
+ // Note: using a queue instead of array for efficiency
43
+ schedulingQueue = (function Queue() {
44
+ var first, last, item;
45
+
46
+ function Item(fn,self) {
47
+ this.fn = fn;
48
+ this.self = self;
49
+ this.next = void 0;
50
+ }
51
+
52
+ return {
53
+ add: function add(fn,self) {
54
+ item = new Item(fn,self);
55
+ if (last) {
56
+ last.next = item;
57
+ }
58
+ else {
59
+ first = item;
60
+ }
61
+ last = item;
62
+ item = void 0;
63
+ },
64
+ drain: function drain() {
65
+ var f = first;
66
+ first = last = cycle = void 0;
67
+
68
+ while (f) {
69
+ f.fn.call(f.self);
70
+ f = f.next;
71
+ }
72
+ }
73
+ };
74
+ })();
75
+
76
+ function schedule(fn,self) {
77
+ schedulingQueue.add(fn,self);
78
+ if (!cycle) {
79
+ cycle = timer(schedulingQueue.drain);
80
+ }
81
+ }
82
+
83
+ // promise duck typing
84
+ function isThenable(o) {
85
+ var _then, oType = typeof o;
86
+
87
+ if (o !== null && (oType === 'object' || oType === 'function')) {
88
+ _then = o.then;
89
+ }
90
+ return typeof _then === 'function' ? _then : false;
91
+ }
92
+
93
+ function notify() {
94
+ for (var i=0; i<this.chain.length; i++) {
95
+ notifyIsolated(
96
+ this,
97
+ (this.state === 1) ? this.chain[i].success : this.chain[i].failure,
98
+ this.chain[i]
99
+ );
100
+ }
101
+ this.chain.length = 0;
102
+ }
103
+
104
+ // NOTE: This is a separate function to isolate
105
+ // the `try..catch` so that other code can be
106
+ // optimized better
107
+ function notifyIsolated(self,cb,chain) {
108
+ var ret, _then;
109
+ try {
110
+ if (cb === false) {
111
+ chain.reject(self.msg);
112
+ }
113
+ else {
114
+ if (cb === true) {
115
+ ret = self.msg;
116
+ }
117
+ else {
118
+ ret = cb.call(void 0,self.msg);
119
+ }
120
+
121
+ if (ret === chain.promise) {
122
+ chain.reject(TypeError('Promise-chain cycle'));
123
+ }
124
+ // eslint-disable-next-line no-cond-assign
125
+ else if (_then = isThenable(ret)) {
126
+ _then.call(ret,chain.resolve,chain.reject);
127
+ }
128
+ else {
129
+ chain.resolve(ret);
130
+ }
131
+ }
132
+ }
133
+ catch (err) {
134
+ chain.reject(err);
135
+ }
136
+ }
137
+
138
+ function resolve(msg) {
139
+ var _then, self = this;
140
+
141
+ // already triggered?
142
+ if (self.triggered) { return; }
143
+
144
+ self.triggered = true;
145
+
146
+ // unwrap
147
+ if (self.def) {
148
+ self = self.def;
149
+ }
150
+
151
+ try {
152
+ // eslint-disable-next-line no-cond-assign
153
+ if (_then = isThenable(msg)) {
154
+ schedule(function(){
155
+ var defWrapper = new MakeDefWrapper(self);
156
+ try {
157
+ _then.call(msg,
158
+ function $resolve$(){ resolve.apply(defWrapper,arguments); },
159
+ function $reject$(){ reject.apply(defWrapper,arguments); }
160
+ );
161
+ }
162
+ catch (err) {
163
+ reject.call(defWrapper,err);
164
+ }
165
+ });
166
+ }
167
+ else {
168
+ self.msg = msg;
169
+ self.state = 1;
170
+ if (self.chain.length > 0) {
171
+ schedule(notify,self);
172
+ }
173
+ }
174
+ }
175
+ catch (err) {
176
+ reject.call(new MakeDefWrapper(self),err);
177
+ }
178
+ }
179
+
180
+ function reject(msg) {
181
+ var self = this;
182
+
183
+ // already triggered?
184
+ if (self.triggered) { return; }
185
+
186
+ self.triggered = true;
187
+
188
+ // unwrap
189
+ if (self.def) {
190
+ self = self.def;
191
+ }
192
+
193
+ self.msg = msg;
194
+ self.state = 2;
195
+ if (self.chain.length > 0) {
196
+ schedule(notify,self);
197
+ }
198
+ }
199
+
200
+ function iteratePromises(Constructor,arr,resolver,rejecter) {
201
+ for (var idx=0; idx<arr.length; idx++) {
202
+ (function IIFE(idx){
203
+ Constructor.resolve(arr[idx])
204
+ .then(
205
+ function $resolver$(msg){
206
+ resolver(idx,msg);
207
+ },
208
+ rejecter
209
+ );
210
+ })(idx);
211
+ }
212
+ }
213
+
214
+ function MakeDefWrapper(self) {
215
+ this.def = self;
216
+ this.triggered = false;
217
+ }
218
+
219
+ function MakeDef(self) {
220
+ this.promise = self;
221
+ this.state = 0;
222
+ this.triggered = false;
223
+ this.chain = [];
224
+ this.msg = void 0;
225
+ }
226
+
227
+ function NpoPromise(executor) {
228
+ if (typeof executor !== 'function') {
229
+ throw TypeError('Not a function');
230
+ }
231
+
232
+ if (this['__NPO__'] !== 0) {
233
+ throw TypeError('Not a promise');
234
+ }
235
+
236
+ // instance shadowing the inherited "brand"
237
+ // to signal an already "initialized" promise
238
+ this['__NPO__'] = 1;
239
+
240
+ var def = new MakeDef(this);
241
+
242
+ this['then'] = function then(success,failure) {
243
+ var o = {
244
+ success: typeof success === 'function' ? success : true,
245
+ failure: typeof failure === 'function' ? failure : false
246
+ };
247
+ // Note: `then(..)` itself can be borrowed to be used against
248
+ // a different promise constructor for making the chained promise,
249
+ // by substituting a different `this` binding.
250
+ o.promise = new this.constructor(function extractChain(resolve,reject) {
251
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
252
+ throw TypeError('Not a function');
253
+ }
254
+
255
+ o.resolve = resolve;
256
+ o.reject = reject;
257
+ });
258
+ def.chain.push(o);
259
+
260
+ if (def.state !== 0) {
261
+ schedule(notify,def);
262
+ }
263
+
264
+ return o.promise;
265
+ };
266
+ this['catch'] = function $catch$(failure) {
267
+ return this.then(void 0,failure);
268
+ };
269
+
270
+ try {
271
+ executor.call(
272
+ void 0,
273
+ function publicResolve(msg){
274
+ resolve.call(def,msg);
275
+ },
276
+ function publicReject(msg) {
277
+ reject.call(def,msg);
278
+ }
279
+ );
280
+ }
281
+ catch (err) {
282
+ reject.call(def,err);
283
+ }
284
+ }
285
+
286
+ var PromisePrototype = builtInProp({},'constructor',NpoPromise,
287
+ /*configurable=*/false
288
+ );
289
+
290
+ // Note: Android 4 cannot use `Object.defineProperty(..)` here
291
+ NpoPromise.prototype = PromisePrototype;
292
+
293
+ // built-in "brand" to signal an "uninitialized" promise
294
+ builtInProp(PromisePrototype,'__NPO__',0,
295
+ /*configurable=*/false
296
+ );
297
+
298
+ builtInProp(NpoPromise,'resolve',function Promise$resolve(msg) {
299
+ var Constructor = this;
300
+
301
+ // spec mandated checks
302
+ // note: best "isPromise" check that's practical for now
303
+ if (msg && typeof msg === 'object' && msg['__NPO__'] === 1) {
304
+ return msg;
305
+ }
306
+
307
+ return new Constructor(function executor(resolve,reject){
308
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
309
+ throw TypeError('Not a function');
310
+ }
311
+
312
+ resolve(msg);
313
+ });
314
+ });
315
+
316
+ builtInProp(NpoPromise,'reject',function Promise$reject(msg) {
317
+ return new this(function executor(resolve,reject){
318
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
319
+ throw TypeError('Not a function');
320
+ }
321
+
322
+ reject(msg);
323
+ });
324
+ });
325
+
326
+ builtInProp(NpoPromise,'all',function Promise$all(arr) {
327
+ var Constructor = this;
328
+
329
+ // spec mandated checks
330
+ if (ToString.call(arr) !== '[object Array]') {
331
+ return Constructor.reject(TypeError('Not an array'));
332
+ }
333
+ if (arr.length === 0) {
334
+ return Constructor.resolve([]);
335
+ }
336
+
337
+ return new Constructor(function executor(resolve,reject){
338
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
339
+ throw TypeError('Not a function');
340
+ }
341
+
342
+ var len = arr.length, msgs = Array(len), count = 0;
343
+
344
+ iteratePromises(Constructor,arr,function resolver(idx,msg) {
345
+ msgs[idx] = msg;
346
+ if (++count === len) {
347
+ resolve(msgs);
348
+ }
349
+ },reject);
350
+ });
351
+ });
352
+
353
+ builtInProp(NpoPromise,'race',function Promise$race(arr) {
354
+ var Constructor = this;
355
+
356
+ // spec mandated checks
357
+ if (ToString.call(arr) !== '[object Array]') {
358
+ return Constructor.reject(TypeError('Not an array'));
359
+ }
360
+
361
+ return new Constructor(function executor(resolve,reject){
362
+ if (typeof resolve !== 'function' || typeof reject !== 'function') {
363
+ throw TypeError('Not a function');
364
+ }
365
+
366
+ iteratePromises(Constructor,arr,function resolver(idx,msg){
367
+ resolve(msg);
368
+ },reject);
369
+ });
370
+ });
371
+
372
+ var PromisePolyfill;
373
+ if (typeof Promise !== 'undefined' && Promise.toString().indexOf('[native code]') !== -1) {
374
+ PromisePolyfill = Promise;
375
+ } else {
376
+ PromisePolyfill = NpoPromise;
377
+ }
378
+
379
+ export { PromisePolyfill as Promise, NpoPromise };
@@ -1,7 +1,8 @@
1
1
  import {record} from 'rrweb';
2
2
 
3
3
  import { SessionRecording } from './session-recording';
4
- import { console_with_prefix, _, window} from '../utils'; // eslint-disable-line camelcase
4
+ import { console_with_prefix, _ } from '../utils'; // eslint-disable-line camelcase
5
+ import { window } from '../window';
5
6
 
6
7
  var logger = console_with_prefix('recorder');
7
8
 
@@ -1,6 +1,7 @@
1
1
  import { IncrementalSource, EventType } from '@rrweb/types';
2
2
 
3
- import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, _, window} from '../utils'; // eslint-disable-line camelcase
3
+ import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, _} from '../utils'; // eslint-disable-line camelcase
4
+ import { window } from '../window';
4
5
  import { addOptOutCheckMixpanelLib } from '../gdpr-utils';
5
6
  import { RequestBatcher } from '../request-batcher';
6
7
  import Config from '../config';
@@ -52,6 +53,7 @@ var SessionRecording = function(options) {
52
53
 
53
54
  this.seqNo = 0;
54
55
  this.replayStartTime = null;
56
+ this.replayStartUrl = null;
55
57
  this.batchStartUrl = null;
56
58
 
57
59
  this.idleTimeoutId = null;
@@ -103,6 +105,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
103
105
 
104
106
  this.replayStartTime = new Date().getTime();
105
107
  this.batchStartUrl = _.info.currentUrl();
108
+ this.replayStartUrl = _.info.currentUrl();
106
109
 
107
110
  if (shouldStopBatcher || this.recordMinMs > 0) {
108
111
  // the primary case for shouldStopBatcher is when we're starting recording after a reset
@@ -139,9 +142,17 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
139
142
  'blockClass': this.getConfig('record_block_class'),
140
143
  'blockSelector': blockSelector,
141
144
  'collectFonts': this.getConfig('record_collect_fonts'),
145
+ 'dataURLOptions': { // canvas image options (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL)
146
+ 'type': 'image/webp',
147
+ 'quality': 0.6
148
+ },
142
149
  'maskAllInputs': true,
143
150
  'maskTextClass': this.getConfig('record_mask_text_class'),
144
- 'maskTextSelector': this.getConfig('record_mask_text_selector')
151
+ 'maskTextSelector': this.getConfig('record_mask_text_selector'),
152
+ 'recordCanvas': this.getConfig('record_canvas'),
153
+ 'sampling': {
154
+ 'canvas': 15
155
+ }
145
156
  });
146
157
 
147
158
  if (typeof this._stopRecording !== 'function') {
@@ -259,6 +270,7 @@ SessionRecording.prototype._flushEvents = addOptOutCheckMixpanelLib(function (da
259
270
  'replay_id': replayId,
260
271
  'replay_length_ms': replayLengthMs,
261
272
  'replay_start_time': this.replayStartTime / 1000,
273
+ 'replay_start_url': this.replayStartUrl,
262
274
  'seq': this.seqNo
263
275
  };
264
276
  var eventsJson = _.JSONEncode(data);