mixpanel-browser 2.53.0 → 2.54.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/.vscode/launch.json +23 -0
- package/CHANGELOG.md +9 -0
- package/README.md +12 -0
- package/build.sh +2 -0
- package/dist/mixpanel-core.cjs.js +6369 -0
- package/dist/mixpanel-recorder.js +982 -109
- package/dist/mixpanel-recorder.min.js +9 -9
- package/dist/mixpanel-with-async-recorder.cjs.js +6371 -0
- package/dist/mixpanel.amd.js +5333 -519
- package/dist/mixpanel.cjs.js +5333 -519
- package/dist/mixpanel.globals.js +166 -114
- package/dist/mixpanel.min.js +108 -108
- package/dist/mixpanel.umd.js +5333 -519
- package/package.json +1 -2
- package/rollup.config.js +3 -3
- package/src/config.js +1 -1
- package/src/loaders/bundle-loaders.js +22 -0
- package/src/loaders/loader-globals.js +2 -1
- package/src/loaders/loader-module-core.js +7 -0
- package/src/loaders/loader-module-with-async-recorder.js +7 -0
- package/src/loaders/loader-module.js +4 -1
- package/src/mixpanel-core.js +18 -11
- package/src/recorder/index.js +129 -37
- package/src/request-batcher.js +24 -13
- package/src/request-queue.js +112 -88
package/src/request-queue.js
CHANGED
|
@@ -26,6 +26,7 @@ var RequestQueue = function(storageKey, options) {
|
|
|
26
26
|
this.reportError = options.errorReporter || _.bind(logger.error, logger);
|
|
27
27
|
this.lock = new SharedLock(storageKey, {storage: this.storage});
|
|
28
28
|
|
|
29
|
+
this.usePersistence = options.usePersistence;
|
|
29
30
|
this.pid = options.pid || null; // pass pid to test out storage lock contention scenarios
|
|
30
31
|
|
|
31
32
|
this.memQueue = [];
|
|
@@ -50,29 +51,36 @@ RequestQueue.prototype.enqueue = function(item, flushInterval, cb) {
|
|
|
50
51
|
'payload': item
|
|
51
52
|
};
|
|
52
53
|
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
var storedQueue = this.readFromStorage();
|
|
57
|
-
storedQueue.push(queueEntry);
|
|
58
|
-
succeeded = this.saveToStorage(storedQueue);
|
|
59
|
-
if (succeeded) {
|
|
60
|
-
// only add to in-memory queue when storage succeeds
|
|
61
|
-
this.memQueue.push(queueEntry);
|
|
62
|
-
}
|
|
63
|
-
} catch(err) {
|
|
64
|
-
this.reportError('Error enqueueing item', item);
|
|
65
|
-
succeeded = false;
|
|
66
|
-
}
|
|
54
|
+
if (!this.usePersistence) {
|
|
55
|
+
this.memQueue.push(queueEntry);
|
|
67
56
|
if (cb) {
|
|
68
|
-
cb(
|
|
57
|
+
cb(true);
|
|
69
58
|
}
|
|
70
|
-
}
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
59
|
+
} else {
|
|
60
|
+
this.lock.withLock(_.bind(function lockAcquired() {
|
|
61
|
+
var succeeded;
|
|
62
|
+
try {
|
|
63
|
+
var storedQueue = this.readFromStorage();
|
|
64
|
+
storedQueue.push(queueEntry);
|
|
65
|
+
succeeded = this.saveToStorage(storedQueue);
|
|
66
|
+
if (succeeded) {
|
|
67
|
+
// only add to in-memory queue when storage succeeds
|
|
68
|
+
this.memQueue.push(queueEntry);
|
|
69
|
+
}
|
|
70
|
+
} catch(err) {
|
|
71
|
+
this.reportError('Error enqueueing item', item);
|
|
72
|
+
succeeded = false;
|
|
73
|
+
}
|
|
74
|
+
if (cb) {
|
|
75
|
+
cb(succeeded);
|
|
76
|
+
}
|
|
77
|
+
}, this), _.bind(function lockFailure(err) {
|
|
78
|
+
this.reportError('Error acquiring storage lock', err);
|
|
79
|
+
if (cb) {
|
|
80
|
+
cb(false);
|
|
81
|
+
}
|
|
82
|
+
}, this), this.pid);
|
|
83
|
+
}
|
|
76
84
|
};
|
|
77
85
|
|
|
78
86
|
/**
|
|
@@ -83,7 +91,7 @@ RequestQueue.prototype.enqueue = function(item, flushInterval, cb) {
|
|
|
83
91
|
*/
|
|
84
92
|
RequestQueue.prototype.fillBatch = function(batchSize) {
|
|
85
93
|
var batch = this.memQueue.slice(0, batchSize);
|
|
86
|
-
if (batch.length < batchSize) {
|
|
94
|
+
if (this.usePersistence && batch.length < batchSize) {
|
|
87
95
|
// don't need lock just to read events; localStorage is thread-safe
|
|
88
96
|
// and the worst that could happen is a duplicate send of some
|
|
89
97
|
// orphaned events, which will be deduplicated on the server side
|
|
@@ -132,61 +140,67 @@ RequestQueue.prototype.removeItemsByID = function(ids, cb) {
|
|
|
132
140
|
_.each(ids, function(id) { idSet[id] = true; });
|
|
133
141
|
|
|
134
142
|
this.memQueue = filterOutIDsAndInvalid(this.memQueue, idSet);
|
|
143
|
+
if (!this.usePersistence) {
|
|
144
|
+
if (cb) {
|
|
145
|
+
cb(true);
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
var removeFromStorage = _.bind(function() {
|
|
149
|
+
var succeeded;
|
|
150
|
+
try {
|
|
151
|
+
var storedQueue = this.readFromStorage();
|
|
152
|
+
storedQueue = filterOutIDsAndInvalid(storedQueue, idSet);
|
|
153
|
+
succeeded = this.saveToStorage(storedQueue);
|
|
135
154
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
storedQueue = this.readFromStorage();
|
|
147
|
-
for (var i = 0; i < storedQueue.length; i++) {
|
|
148
|
-
var item = storedQueue[i];
|
|
149
|
-
if (item['id'] && !!idSet[item['id']]) {
|
|
150
|
-
this.reportError('Item not removed from storage');
|
|
151
|
-
return false;
|
|
155
|
+
// an extra check: did storage report success but somehow
|
|
156
|
+
// the items are still there?
|
|
157
|
+
if (succeeded) {
|
|
158
|
+
storedQueue = this.readFromStorage();
|
|
159
|
+
for (var i = 0; i < storedQueue.length; i++) {
|
|
160
|
+
var item = storedQueue[i];
|
|
161
|
+
if (item['id'] && !!idSet[item['id']]) {
|
|
162
|
+
this.reportError('Item not removed from storage');
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
152
165
|
}
|
|
153
166
|
}
|
|
167
|
+
} catch(err) {
|
|
168
|
+
this.reportError('Error removing items', ids);
|
|
169
|
+
succeeded = false;
|
|
154
170
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
succeeded = false;
|
|
158
|
-
}
|
|
159
|
-
return succeeded;
|
|
160
|
-
}, this);
|
|
171
|
+
return succeeded;
|
|
172
|
+
}, this);
|
|
161
173
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
this.lock.withLock(function lockAcquired() {
|
|
175
|
+
var succeeded = removeFromStorage();
|
|
176
|
+
if (cb) {
|
|
177
|
+
cb(succeeded);
|
|
178
|
+
}
|
|
179
|
+
}, _.bind(function lockFailure(err) {
|
|
180
|
+
var succeeded = false;
|
|
181
|
+
this.reportError('Error acquiring storage lock', err);
|
|
182
|
+
if (!localStorageSupported(this.storage, true)) {
|
|
183
|
+
// Looks like localStorage writes have stopped working sometime after
|
|
184
|
+
// initialization (probably full), and so nobody can acquire locks
|
|
185
|
+
// anymore. Consider it temporarily safe to remove items without the
|
|
186
|
+
// lock, since nobody's writing successfully anyway.
|
|
187
|
+
succeeded = removeFromStorage();
|
|
188
|
+
if (!succeeded) {
|
|
189
|
+
// OK, we couldn't even write out the smaller queue. Try clearing it
|
|
190
|
+
// entirely.
|
|
191
|
+
try {
|
|
192
|
+
this.storage.removeItem(this.storageKey);
|
|
193
|
+
} catch(err) {
|
|
194
|
+
this.reportError('Error clearing queue', err);
|
|
195
|
+
}
|
|
183
196
|
}
|
|
184
197
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
}
|
|
198
|
+
if (cb) {
|
|
199
|
+
cb(succeeded);
|
|
200
|
+
}
|
|
201
|
+
}, this), this.pid);
|
|
202
|
+
}
|
|
203
|
+
|
|
190
204
|
};
|
|
191
205
|
|
|
192
206
|
// internal helper for RequestQueue.updatePayloads
|
|
@@ -214,25 +228,32 @@ var updatePayloads = function(existingItems, itemsToUpdate) {
|
|
|
214
228
|
*/
|
|
215
229
|
RequestQueue.prototype.updatePayloads = function(itemsToUpdate, cb) {
|
|
216
230
|
this.memQueue = updatePayloads(this.memQueue, itemsToUpdate);
|
|
217
|
-
this.
|
|
218
|
-
var succeeded;
|
|
219
|
-
try {
|
|
220
|
-
var storedQueue = this.readFromStorage();
|
|
221
|
-
storedQueue = updatePayloads(storedQueue, itemsToUpdate);
|
|
222
|
-
succeeded = this.saveToStorage(storedQueue);
|
|
223
|
-
} catch(err) {
|
|
224
|
-
this.reportError('Error updating items', itemsToUpdate);
|
|
225
|
-
succeeded = false;
|
|
226
|
-
}
|
|
227
|
-
if (cb) {
|
|
228
|
-
cb(succeeded);
|
|
229
|
-
}
|
|
230
|
-
}, this), _.bind(function lockFailure(err) {
|
|
231
|
-
this.reportError('Error acquiring storage lock', err);
|
|
231
|
+
if (!this.usePersistence) {
|
|
232
232
|
if (cb) {
|
|
233
|
-
cb(
|
|
233
|
+
cb(true);
|
|
234
234
|
}
|
|
235
|
-
}
|
|
235
|
+
} else {
|
|
236
|
+
this.lock.withLock(_.bind(function lockAcquired() {
|
|
237
|
+
var succeeded;
|
|
238
|
+
try {
|
|
239
|
+
var storedQueue = this.readFromStorage();
|
|
240
|
+
storedQueue = updatePayloads(storedQueue, itemsToUpdate);
|
|
241
|
+
succeeded = this.saveToStorage(storedQueue);
|
|
242
|
+
} catch(err) {
|
|
243
|
+
this.reportError('Error updating items', itemsToUpdate);
|
|
244
|
+
succeeded = false;
|
|
245
|
+
}
|
|
246
|
+
if (cb) {
|
|
247
|
+
cb(succeeded);
|
|
248
|
+
}
|
|
249
|
+
}, this), _.bind(function lockFailure(err) {
|
|
250
|
+
this.reportError('Error acquiring storage lock', err);
|
|
251
|
+
if (cb) {
|
|
252
|
+
cb(false);
|
|
253
|
+
}
|
|
254
|
+
}, this), this.pid);
|
|
255
|
+
}
|
|
256
|
+
|
|
236
257
|
};
|
|
237
258
|
|
|
238
259
|
/**
|
|
@@ -275,7 +296,10 @@ RequestQueue.prototype.saveToStorage = function(queue) {
|
|
|
275
296
|
*/
|
|
276
297
|
RequestQueue.prototype.clear = function() {
|
|
277
298
|
this.memQueue = [];
|
|
278
|
-
|
|
299
|
+
|
|
300
|
+
if (this.usePersistence) {
|
|
301
|
+
this.storage.removeItem(this.storageKey);
|
|
302
|
+
}
|
|
279
303
|
};
|
|
280
304
|
|
|
281
305
|
export { RequestQueue };
|