mixpanel-browser 2.78.0 → 2.80.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.
Files changed (67) hide show
  1. package/.eslintrc.json +12 -0
  2. package/.github/workflows/integration-tests.yml +1 -0
  3. package/.github/workflows/openfeature-provider-tests.yml +31 -0
  4. package/CHANGELOG.md +14 -1
  5. package/build.sh +2 -2
  6. package/dist/async-modules/{mixpanel-recorder-BjSlYaNJ.min.js → mixpanel-recorder-B61POiHc.min.js} +2 -2
  7. package/dist/async-modules/mixpanel-recorder-B61POiHc.min.js.map +1 -0
  8. package/dist/async-modules/{mixpanel-recorder-zMBXIyeG.js → mixpanel-recorder-C3AW7mPl.js} +63 -35
  9. package/dist/async-modules/{mixpanel-targeting-UHf4eBfC.js → mixpanel-targeting-CBwOQJZw.js} +24 -13
  10. package/dist/async-modules/mixpanel-targeting-kdl-eE-1.min.js +2 -0
  11. package/dist/async-modules/mixpanel-targeting-kdl-eE-1.min.js.map +1 -0
  12. package/dist/mixpanel-core.cjs.d.ts +45 -1
  13. package/dist/mixpanel-core.cjs.js +577 -209
  14. package/dist/mixpanel-recorder.js +63 -35
  15. package/dist/mixpanel-recorder.min.js +1 -1
  16. package/dist/mixpanel-recorder.min.js.map +1 -1
  17. package/dist/mixpanel-targeting.js +24 -13
  18. package/dist/mixpanel-targeting.min.js +1 -1
  19. package/dist/mixpanel-targeting.min.js.map +1 -1
  20. package/dist/mixpanel-with-async-modules.cjs.d.ts +45 -1
  21. package/dist/mixpanel-with-async-modules.cjs.js +579 -211
  22. package/dist/mixpanel-with-async-recorder.cjs.d.ts +45 -1
  23. package/dist/mixpanel-with-async-recorder.cjs.js +579 -211
  24. package/dist/mixpanel-with-recorder.d.ts +45 -1
  25. package/dist/mixpanel-with-recorder.js +508 -136
  26. package/dist/mixpanel-with-recorder.min.d.ts +45 -1
  27. package/dist/mixpanel-with-recorder.min.js +1 -1
  28. package/dist/mixpanel.amd.d.ts +45 -1
  29. package/dist/mixpanel.amd.js +508 -136
  30. package/dist/mixpanel.cjs.d.ts +45 -1
  31. package/dist/mixpanel.cjs.js +508 -136
  32. package/dist/mixpanel.globals.js +579 -211
  33. package/dist/mixpanel.min.js +200 -190
  34. package/dist/mixpanel.module.d.ts +45 -1
  35. package/dist/mixpanel.module.js +508 -136
  36. package/dist/mixpanel.umd.d.ts +45 -1
  37. package/dist/mixpanel.umd.js +508 -136
  38. package/package.json +1 -1
  39. package/packages/openfeature-web-provider/README.md +357 -0
  40. package/packages/openfeature-web-provider/package-lock.json +1636 -0
  41. package/packages/openfeature-web-provider/package.json +51 -0
  42. package/packages/openfeature-web-provider/rollup.config.browser.mjs +26 -0
  43. package/packages/openfeature-web-provider/src/MixpanelProvider.ts +302 -0
  44. package/packages/openfeature-web-provider/src/index.ts +1 -0
  45. package/packages/openfeature-web-provider/src/types.ts +72 -0
  46. package/packages/openfeature-web-provider/test/MixpanelProvider.spec.ts +484 -0
  47. package/packages/openfeature-web-provider/tsconfig.json +15 -0
  48. package/src/autocapture/index.js +17 -12
  49. package/src/config.js +1 -1
  50. package/src/flags/flags-persistence.js +176 -0
  51. package/src/flags/index.js +176 -25
  52. package/src/index.d.ts +45 -1
  53. package/src/mixpanel-core.js +24 -7
  54. package/src/recorder/idb-config.js +16 -0
  55. package/src/recorder/recording-registry.js +7 -2
  56. package/src/recorder/session-recording.js +15 -6
  57. package/src/recorder-manager.js +7 -2
  58. package/src/request-queue.js +1 -2
  59. package/src/shared-lock.js +2 -3
  60. package/src/storage/indexed-db.js +16 -15
  61. package/src/storage/local-storage.js +5 -3
  62. package/src/utils.js +25 -12
  63. package/tsconfig.base.json +9 -0
  64. package/.claude/settings.local.json +0 -16
  65. package/dist/async-modules/mixpanel-recorder-BjSlYaNJ.min.js.map +0 -1
  66. package/dist/async-modules/mixpanel-targeting-BSHal4N9.min.js +0 -2
  67. package/dist/async-modules/mixpanel-targeting-BSHal4N9.min.js.map +0 -1
@@ -1,5 +1,10 @@
1
1
  import { Promise } from '../promise-polyfill';
2
- import { IDBStorageWrapper, RECORDING_REGISTRY_STORE_NAME } from '../storage/indexed-db';
2
+ import { IDBStorageWrapper } from '../storage/indexed-db';
3
+ import {
4
+ MIXPANEL_BROWSER_DB_NAME,
5
+ RECORDING_REGISTRY_STORE_NAME,
6
+ RECORDER_VERSION_DATA
7
+ } from './idb-config';
3
8
  import { SessionRecording } from './session-recording';
4
9
  import { isRecordingExpired } from './utils';
5
10
 
@@ -9,7 +14,7 @@ import { isRecordingExpired } from './utils';
9
14
  */
10
15
  var RecordingRegistry = function (options) {
11
16
  /** @type {IDBStorageWrapper} */
12
- this.idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
17
+ this.idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
13
18
  this.errorReporter = options.errorReporter;
14
19
  this.mixpanelInstance = options.mixpanelInstance;
15
20
  this.sharedLockStorage = options.sharedLockStorage;
@@ -4,8 +4,13 @@
4
4
 
5
5
  import { window } from '../window';
6
6
  import { EventType, getRecordConsolePlugin, IncrementalSource } from './rrweb-entrypoint';
7
- import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, NOOP_FUNC, _, localStorageSupported, canUseCompressionStream, navigator, userAgent, windowOpera} from '../utils'; // eslint-disable-line camelcase
8
- import { IDBStorageWrapper, RECORDING_EVENTS_STORE_NAME } from '../storage/indexed-db';
7
+ import { MAX_RECORDING_MS, MAX_VALUE_FOR_MIN_RECORDING_MS, console_with_prefix, NOOP_FUNC, _, localStorageSupported, getLocalStorage, canUseCompressionStream, navigator, userAgent, windowOpera} from '../utils'; // eslint-disable-line camelcase
8
+ import { IDBStorageWrapper } from '../storage/indexed-db';
9
+ import {
10
+ MIXPANEL_BROWSER_DB_NAME,
11
+ RECORDING_EVENTS_STORE_NAME,
12
+ RECORDER_VERSION_DATA
13
+ } from './idb-config';
9
14
  import { addOptOutCheckMixpanelLib } from '../gdpr-utils';
10
15
  import { RequestBatcher } from '../request-batcher';
11
16
 
@@ -108,14 +113,15 @@ var SessionRecording = function(options) {
108
113
 
109
114
  this.recordMaxMs = MAX_RECORDING_MS;
110
115
  this.recordMinMs = 0;
116
+ this._recordMinMsCheckStart = null;
111
117
 
112
118
  // disable persistence if localStorage is not supported
113
119
  // request-queue will automatically disable persistence if indexedDB fails to initialize
114
- var usePersistence = localStorageSupported(options.sharedLockStorage, true) && !this.getConfig('disable_persistence');
120
+ var usePersistence = localStorageSupported(options.sharedLockStorage || getLocalStorage(), true) && !this.getConfig('disable_persistence');
115
121
 
116
122
  // each replay has its own batcher key to avoid conflicts between rrweb events of different recordings
117
123
  this.batcherKey = '__mprec_' + this.getConfig('name') + '_' + this.getConfig('token') + '_' + this.replayId;
118
- this.queueStorage = new IDBStorageWrapper(RECORDING_EVENTS_STORE_NAME);
124
+ this.queueStorage = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_EVENTS_STORE_NAME, RECORDER_VERSION_DATA);
119
125
  this.batcher = new RequestBatcher(this.batcherKey, {
120
126
  errorReporter: this.reportError.bind(this),
121
127
  flushOnlyOnInterval: true,
@@ -223,6 +229,7 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
223
229
  // this also applies if the minimum recording length has not been hit yet
224
230
  // so that we don't send data until we know the recording will be long enough
225
231
  this.batcher.stop();
232
+ this._recordMinMsCheckStart = null;
226
233
  } else {
227
234
  this.batcher.start();
228
235
  }
@@ -274,9 +281,11 @@ SessionRecording.prototype.startRecording = function (shouldStopBatcher) {
274
281
  this._onIdleTimeout();
275
282
  return;
276
283
  }
284
+ if (this._recordMinMsCheckStart === null) {
285
+ this._recordMinMsCheckStart = ev.timestamp;
286
+ }
277
287
  if (isUserEvent(ev)) {
278
- if (this.batcher.stopped && new Date().getTime() - this.replayStartTime >= this.recordMinMs) {
279
- // start flushing again after user activity
288
+ if (this.batcher.stopped && ev.timestamp - this._recordMinMsCheckStart >= this.recordMinMs) {
280
289
  this.batcher.start();
281
290
  }
282
291
  resetIdleTimeout();
@@ -4,7 +4,12 @@ import {RECORDER_FILENAME, TARGETING_FILENAME, RECORDER_GLOBAL_NAME} from './con
4
4
  import { _, console, console_with_prefix, safewrap, safewrapClass } from './utils';
5
5
  import { window } from './window';
6
6
  import { Promise } from './promise-polyfill';
7
- import { IDBStorageWrapper, RECORDING_REGISTRY_STORE_NAME } from './storage/indexed-db';
7
+ import { IDBStorageWrapper } from './storage/indexed-db';
8
+ import {
9
+ MIXPANEL_BROWSER_DB_NAME,
10
+ RECORDING_REGISTRY_STORE_NAME,
11
+ RECORDER_VERSION_DATA
12
+ } from './recorder/idb-config';
8
13
  import { isRecordingExpired, validateAllowedOrigins } from './recorder/utils';
9
14
  import { getTargetingPromise } from './targeting/loader';
10
15
 
@@ -43,7 +48,7 @@ RecorderManager.prototype.shouldLoadRecorder = function() {
43
48
  return Promise.resolve(false);
44
49
  }
45
50
 
46
- var recording_registry_idb = new IDBStorageWrapper(RECORDING_REGISTRY_STORE_NAME);
51
+ var recording_registry_idb = new IDBStorageWrapper(MIXPANEL_BROWSER_DB_NAME, RECORDING_REGISTRY_STORE_NAME, RECORDER_VERSION_DATA);
47
52
  var tab_id = this.getTabId();
48
53
  return recording_registry_idb.init()
49
54
  .then(function () {
@@ -1,6 +1,5 @@
1
1
  import { SharedLock } from './shared-lock';
2
2
  import { batchedThrottle, cheap_guid, console_with_prefix, localStorageSupported, _ } from './utils'; // eslint-disable-line camelcase
3
- import { window } from './window';
4
3
  import { LocalStorageWrapper } from './storage/local-storage';
5
4
  import { Promise } from './promise-polyfill';
6
5
 
@@ -29,7 +28,7 @@ var RequestQueue = function (storageKey, options) {
29
28
  if (this.usePersistence) {
30
29
  this.queueStorage = options.queueStorage || new LocalStorageWrapper();
31
30
  this.lock = new SharedLock(storageKey, {
32
- storage: options.sharedLockStorage || window.localStorage,
31
+ storage: options.sharedLockStorage,
33
32
  timeoutMS: options.sharedLockTimeoutMS,
34
33
  });
35
34
  }
@@ -1,6 +1,5 @@
1
1
  import { Promise } from './promise-polyfill';
2
- import { console_with_prefix, localStorageSupported, _ } from './utils'; // eslint-disable-line camelcase
3
- import { window } from './window';
2
+ import { console_with_prefix, localStorageSupported, getLocalStorage, _ } from './utils'; // eslint-disable-line camelcase
4
3
 
5
4
  var logger = console_with_prefix('lock');
6
5
 
@@ -28,7 +27,7 @@ var SharedLock = function(key, options) {
28
27
  options = options || {};
29
28
 
30
29
  this.storageKey = key;
31
- this.storage = options.storage || window.localStorage;
30
+ this.storage = options.storage || getLocalStorage();
32
31
  this.pollIntervalMS = options.pollIntervalMS || 100;
33
32
  this.timeoutMS = options.timeoutMS || 2000;
34
33
 
@@ -1,29 +1,26 @@
1
1
  import { Promise } from '../promise-polyfill';
2
2
  import { window } from '../window';
3
3
 
4
- var MIXPANEL_DB_NAME = 'mixpanelBrowserDb';
5
-
6
- var RECORDING_EVENTS_STORE_NAME = 'mixpanelRecordingEvents';
7
- var RECORDING_REGISTRY_STORE_NAME = 'mixpanelRecordingRegistry';
8
-
9
- // note: increment the version number when adding new object stores
10
- var DB_VERSION = 1;
11
- var OBJECT_STORES = [RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME];
12
-
13
4
  /**
14
5
  * @type {import('./wrapper').StorageWrapper}
15
6
  */
16
- var IDBStorageWrapper = function (storeName) {
7
+ var IDBStorageWrapper = function (dbName, storeName, versionData) {
8
+ this.dbName = dbName;
9
+ this.storeName = storeName;
10
+ this.version = versionData.version;
11
+ this.storeNamesInDb = versionData.storeNames;
17
12
  /**
18
13
  * @type {Promise<IDBDatabase>|null}
19
14
  */
20
15
  this.dbPromise = null;
21
- this.storeName = storeName;
22
16
  };
23
17
 
24
18
  IDBStorageWrapper.prototype._openDb = function () {
19
+ var dbName = this.dbName;
20
+ var version = this.version;
21
+ var storeNamesInDb = this.storeNamesInDb;
25
22
  return new Promise(function (resolve, reject) {
26
- var openRequest = window.indexedDB.open(MIXPANEL_DB_NAME, DB_VERSION);
23
+ var openRequest = window.indexedDB.open(dbName, version);
27
24
  openRequest['onerror'] = function () {
28
25
  reject(openRequest.error);
29
26
  };
@@ -35,8 +32,10 @@ IDBStorageWrapper.prototype._openDb = function () {
35
32
  openRequest['onupgradeneeded'] = function (ev) {
36
33
  var db = ev.target.result;
37
34
 
38
- OBJECT_STORES.forEach(function (storeName) {
39
- db.createObjectStore(storeName);
35
+ storeNamesInDb.forEach(function (storeName) {
36
+ if (!db.objectStoreNames.contains(storeName)) {
37
+ db.createObjectStore(storeName);
38
+ }
40
39
  });
41
40
  };
42
41
  });
@@ -128,4 +127,6 @@ IDBStorageWrapper.prototype.getAll = function () {
128
127
  });
129
128
  };
130
129
 
131
- export { IDBStorageWrapper, RECORDING_EVENTS_STORE_NAME, RECORDING_REGISTRY_STORE_NAME };
130
+ export {
131
+ IDBStorageWrapper
132
+ };
@@ -1,15 +1,17 @@
1
1
  import { Promise } from '../promise-polyfill';
2
- import { _, JSONParse, JSONStringify } from '../utils'; // eslint-disable-line camelcase
3
- import { window } from '../window';
2
+ import { _, JSONParse, JSONStringify, getLocalStorage } from '../utils'; // eslint-disable-line camelcase
4
3
 
5
4
  /**
6
5
  * @type {import('./wrapper').StorageWrapper}
7
6
  */
8
7
  var LocalStorageWrapper = function (storageOverride) {
9
- this.storage = storageOverride || window.localStorage;
8
+ this.storage = storageOverride || getLocalStorage();
10
9
  };
11
10
 
12
11
  LocalStorageWrapper.prototype.init = function () {
12
+ if (!this.storage) {
13
+ return Promise.reject(new Error('localStorage is not available'));
14
+ }
13
15
  return Promise.resolve();
14
16
  };
15
17
 
package/src/utils.js CHANGED
@@ -104,6 +104,7 @@ var log_func_with_prefix = function(func, prefix) {
104
104
  var console_with_prefix = function(prefix) {
105
105
  return {
106
106
  log: log_func_with_prefix(console.log, prefix),
107
+ warn: log_func_with_prefix(console.warn, prefix),
107
108
  error: log_func_with_prefix(console.error, prefix),
108
109
  critical: log_func_with_prefix(console.critical, prefix)
109
110
  };
@@ -1050,7 +1051,8 @@ var localStorageSupported = function(storage, forceCheck) {
1050
1051
  if (_localStorageSupported !== null && !forceCheck) {
1051
1052
  return _localStorageSupported;
1052
1053
  }
1053
- return _localStorageSupported = _testStorageSupported(storage || window.localStorage);
1054
+
1055
+ return _localStorageSupported = _testStorageSupported(storage);
1054
1056
  };
1055
1057
 
1056
1058
  var _sessionStorageSupported = null;
@@ -1058,7 +1060,8 @@ var sessionStorageSupported = function(storage, forceCheck) {
1058
1060
  if (_sessionStorageSupported !== null && !forceCheck) {
1059
1061
  return _sessionStorageSupported;
1060
1062
  }
1061
- return _sessionStorageSupported = _testStorageSupported(storage || window.sessionStorage);
1063
+
1064
+ return _sessionStorageSupported = _testStorageSupported(storage);
1062
1065
  };
1063
1066
 
1064
1067
  function _storageWrapper(storage, name, is_supported_fn) {
@@ -1108,17 +1111,26 @@ function _storageWrapper(storage, name, is_supported_fn) {
1108
1111
  };
1109
1112
  }
1110
1113
 
1111
- // Safari errors out accessing localStorage/sessionStorage when cookies are disabled,
1112
- // so create dummy storage wrappers that silently fail as a fallback.
1113
- var windowLocalStorage = null, windowSessionStorage = null;
1114
- try {
1115
- windowLocalStorage = window.localStorage;
1116
- windowSessionStorage = window.sessionStorage;
1117
- // eslint-disable-next-line no-empty
1118
- } catch (_err) {}
1114
+ // Safari and other browsers may error out accessing localStorage/sessionStorage
1115
+ // when cookies are disabled, so wrap access in a try-catch.
1116
+ var getLocalStorage = function() {
1117
+ try {
1118
+ return window.localStorage; // eslint-disable-line no-restricted-properties
1119
+ } catch (_err) {
1120
+ return null;
1121
+ }
1122
+ };
1123
+
1124
+ var getSessionStorage = function() {
1125
+ try {
1126
+ return window.sessionStorage; // eslint-disable-line no-restricted-properties
1127
+ } catch (_err) {
1128
+ return null;
1129
+ }
1130
+ };
1119
1131
 
1120
- _.localStorage = _storageWrapper(windowLocalStorage, 'localStorage', localStorageSupported);
1121
- _.sessionStorage = _storageWrapper(windowSessionStorage, 'sessionStorage', sessionStorageSupported);
1132
+ _.localStorage = _storageWrapper(getLocalStorage(), 'localStorage', localStorageSupported);
1133
+ _.sessionStorage = _storageWrapper(getSessionStorage(), 'sessionStorage', sessionStorageSupported);
1122
1134
 
1123
1135
  _.register_event = (function() {
1124
1136
  // written by Dean Edwards, 2005
@@ -1810,5 +1822,6 @@ export {
1810
1822
  slice,
1811
1823
  urlMatchesRegexList,
1812
1824
  userAgent,
1825
+ getLocalStorage,
1813
1826
  windowOpera,
1814
1827
  };
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "strict": true,
4
+ "esModuleInterop": true,
5
+ "skipLibCheck": true,
6
+ "forceConsistentCasingInFileNames": true,
7
+ "moduleResolution": "node"
8
+ }
9
+ }
@@ -1,16 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(mkdir:*)",
5
- "Bash(cat:*)",
6
- "Bash(node --input-type=module -e \"import { expect } from 'chai'; console.log\\('works'\\);\":*)",
7
- "Bash(BABEL_ENV=test node:*)",
8
- "Bash(npm test)",
9
- "Bash(grep -E \"\\\\.\\(js|json\\)$\")",
10
- "mcp__plugin_Notion_notion__notion-fetch",
11
- "Bash(grep -rn \"sessionStorage\" /home/jakub_grzegorzewski/mixpanel-js/src/*.js)"
12
- ],
13
- "deny": [],
14
- "ask": []
15
- }
16
- }