@leanbase-giangnd/js 0.1.2 → 0.1.5

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/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { isArray, isNullish, isFormData, hasOwnProperty, isString, isNull, isNumber, PostHogPersistedProperty, isUndefined, isFile, isFunction, includes, stripLeadingDollar, isObject, isEmptyObject, trim, isBoolean, clampToRange, BucketedRateLimiter, PostHogCore, getFetch, isEmptyString } from '@posthog/core';
1
+ import { isArray, isNullish, isFormData, hasOwnProperty, isString, isNull, isNumber, PostHogPersistedProperty, isUndefined, isFunction, includes, stripLeadingDollar, isObject, isEmptyObject, trim, isBoolean, clampToRange, BucketedRateLimiter, PostHogCore, getFetch, isEmptyString } from '@posthog/core';
2
2
  import { record } from '@rrweb/record';
3
3
  import { strFromU8, gzipSync, strToU8 } from 'fflate';
4
4
 
@@ -228,7 +228,7 @@ PostHogPersistedProperty.Queue, PostHogPersistedProperty.FeatureFlagDetails, Pos
228
228
 
229
229
  /* eslint-disable no-console */
230
230
  const PREFIX = '[Leanbase]';
231
- const logger$3 = {
231
+ const logger$2 = {
232
232
  info: (...args) => {
233
233
  if (typeof console !== 'undefined') {
234
234
  console.log(PREFIX, ...args);
@@ -526,7 +526,7 @@ function chooseCookieDomain(hostname, cross_subdomain) {
526
526
  if (!matchedSubDomain) {
527
527
  const originalMatch = originalCookieDomainFn(hostname);
528
528
  if (originalMatch !== matchedSubDomain) {
529
- logger$3.info('Warning: cookie subdomain discovery mismatch', originalMatch, matchedSubDomain);
529
+ logger$2.info('Warning: cookie subdomain discovery mismatch', originalMatch, matchedSubDomain);
530
530
  }
531
531
  matchedSubDomain = originalMatch;
532
532
  }
@@ -538,7 +538,7 @@ function chooseCookieDomain(hostname, cross_subdomain) {
538
538
  const cookieStore = {
539
539
  _is_supported: () => !!document,
540
540
  _error: function (msg) {
541
- logger$3.error('cookieStore error: ' + msg);
541
+ logger$2.error('cookieStore error: ' + msg);
542
542
  },
543
543
  _get: function (name) {
544
544
  if (!document) {
@@ -587,7 +587,7 @@ const cookieStore = {
587
587
  const new_cookie_val = name + '=' + encodeURIComponent(JSON.stringify(value)) + expires + '; SameSite=Lax; path=/' + cdomain + secure;
588
588
  // 4096 bytes is the size at which some browsers (e.g. firefox) will not store a cookie, warn slightly before that
589
589
  if (new_cookie_val.length > 4096 * 0.9) {
590
- logger$3.warn('cookieStore warning: large cookie, len=' + new_cookie_val.length);
590
+ logger$2.warn('cookieStore warning: large cookie, len=' + new_cookie_val.length);
591
591
  }
592
592
  document.cookie = new_cookie_val;
593
593
  return new_cookie_val;
@@ -629,13 +629,13 @@ const localStore = {
629
629
  supported = false;
630
630
  }
631
631
  if (!supported) {
632
- logger$3.error('localStorage unsupported; falling back to cookie store');
632
+ logger$2.error('localStorage unsupported; falling back to cookie store');
633
633
  }
634
634
  _localStorage_supported = supported;
635
635
  return supported;
636
636
  },
637
637
  _error: function (msg) {
638
- logger$3.error('localStorage error: ' + msg);
638
+ logger$2.error('localStorage error: ' + msg);
639
639
  },
640
640
  _get: function (name) {
641
641
  try {
@@ -721,7 +721,7 @@ const memoryStore = {
721
721
  return true;
722
722
  },
723
723
  _error: function (msg) {
724
- logger$3.error('memoryStorage error: ' + msg);
724
+ logger$2.error('memoryStorage error: ' + msg);
725
725
  },
726
726
  _get: function (name) {
727
727
  return memoryStorage[name] || null;
@@ -762,7 +762,7 @@ const sessionStore = {
762
762
  return sessionStorageSupported;
763
763
  },
764
764
  _error: function (msg) {
765
- logger$3.error('sessionStorage error: ', msg);
765
+ logger$2.error('sessionStorage error: ', msg);
766
766
  },
767
767
  _get: function (name) {
768
768
  try {
@@ -811,21 +811,6 @@ const convertToURL = url => {
811
811
  location.href = url;
812
812
  return location;
813
813
  };
814
- const formDataToQuery = function (formdata, arg_separator = '&') {
815
- let use_val;
816
- let use_key;
817
- const tph_arr = [];
818
- each(formdata, function (val, key) {
819
- // the key might be literally the string undefined for e.g. if {undefined: 'something'}
820
- if (isUndefined(val) || isUndefined(key) || key === 'undefined') {
821
- return;
822
- }
823
- use_val = encodeURIComponent(isFile(val) ? val.name : val.toString());
824
- use_key = encodeURIComponent(key);
825
- tph_arr[tph_arr.length] = use_key + '=' + use_val;
826
- });
827
- return tph_arr.join(arg_separator);
828
- };
829
814
  // NOTE: Once we get rid of IE11/op_mini we can start using URLSearchParams
830
815
  const getQueryParam = function (url, param) {
831
816
  const withoutHash = url.split('#')[0] || '';
@@ -849,7 +834,7 @@ const getQueryParam = function (url, param) {
849
834
  try {
850
835
  result = decodeURIComponent(result);
851
836
  } catch {
852
- logger$3.error('Skipping decoding for malformed query param: ' + result);
837
+ logger$2.error('Skipping decoding for malformed query param: ' + result);
853
838
  }
854
839
  return result.replace(/\+/g, ' ');
855
840
  }
@@ -1183,7 +1168,7 @@ const detectDeviceType = function (user_agent) {
1183
1168
  }
1184
1169
  };
1185
1170
 
1186
- var version = "0.1.2";
1171
+ var version = "0.1.5";
1187
1172
  var packageInfo = {
1188
1173
  version: version};
1189
1174
 
@@ -1448,7 +1433,7 @@ class LeanbasePersistence {
1448
1433
  this._storage = this._buildStorage(config);
1449
1434
  this.load();
1450
1435
  if (config.debug) {
1451
- logger$3.info('Persistence loaded', config['persistence'], {
1436
+ logger$2.info('Persistence loaded', config['persistence'], {
1452
1437
  ...this.props
1453
1438
  });
1454
1439
  }
@@ -1464,7 +1449,7 @@ class LeanbasePersistence {
1464
1449
  }
1465
1450
  _buildStorage(config) {
1466
1451
  if (CASE_INSENSITIVE_PERSISTENCE_TYPES.indexOf(config['persistence'].toLowerCase()) === -1) {
1467
- logger$3.info('Unknown persistence type ' + config['persistence'] + '; falling back to localStorage+cookie');
1452
+ logger$2.info('Unknown persistence type ' + config['persistence'] + '; falling back to localStorage+cookie');
1468
1453
  config['persistence'] = 'localStorage+cookie';
1469
1454
  }
1470
1455
  let store;
@@ -2100,7 +2085,7 @@ function getNestedSpanText(target) {
2100
2085
  text = `${text} ${getNestedSpanText(child)}`.trim();
2101
2086
  }
2102
2087
  } catch (e) {
2103
- logger$3.error('[AutoCapture]', e);
2088
+ logger$2.error('[AutoCapture]', e);
2104
2089
  }
2105
2090
  }
2106
2091
  });
@@ -2402,7 +2387,7 @@ class Autocapture {
2402
2387
  }
2403
2388
  _addDomEventHandlers() {
2404
2389
  if (!this.isBrowserSupported()) {
2405
- logger$3.info('Disabling Automatic Event Collection because this browser is not supported');
2390
+ logger$2.info('Disabling Automatic Event Collection because this browser is not supported');
2406
2391
  return;
2407
2392
  }
2408
2393
  if (!win || !document) {
@@ -2413,7 +2398,7 @@ class Autocapture {
2413
2398
  try {
2414
2399
  this._captureEvent(e);
2415
2400
  } catch (error) {
2416
- logger$3.error('Failed to capture event', error);
2401
+ logger$2.error('Failed to capture event', error);
2417
2402
  }
2418
2403
  };
2419
2404
  addEventListener(document, 'submit', handler, {
@@ -2598,7 +2583,7 @@ class SessionIdManager {
2598
2583
  this._windowIdGenerator = windowIdGenerator || uuidv7;
2599
2584
  const persistenceName = this._config['persistence_name'] || this._config['token'];
2600
2585
  const desiredTimeout = this._config['session_idle_timeout_seconds'] || DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS;
2601
- this._sessionTimeoutMs = clampToRange(desiredTimeout, MIN_SESSION_IDLE_TIMEOUT_SECONDS, MAX_SESSION_IDLE_TIMEOUT_SECONDS, logger$3, DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS) * 1000;
2586
+ this._sessionTimeoutMs = clampToRange(desiredTimeout, MIN_SESSION_IDLE_TIMEOUT_SECONDS, MAX_SESSION_IDLE_TIMEOUT_SECONDS, logger$2, DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS) * 1000;
2602
2587
  instance.register({
2603
2588
  $configured_session_timeout_ms: this._sessionTimeoutMs
2604
2589
  });
@@ -2625,7 +2610,7 @@ class SessionIdManager {
2625
2610
  const sessionStartTimestamp = uuid7ToTimestampMs(this._config.bootstrap.sessionID);
2626
2611
  this._setSessionId(this._config.bootstrap.sessionID, new Date().getTime(), sessionStartTimestamp);
2627
2612
  } catch (e) {
2628
- logger$3.error('Invalid sessionID in bootstrap', e);
2613
+ logger$2.error('Invalid sessionID in bootstrap', e);
2629
2614
  }
2630
2615
  }
2631
2616
  this._listenToReloadWindow();
@@ -2766,7 +2751,7 @@ class SessionIdManager {
2766
2751
  if (noSessionId || activityTimeout || sessionPastMaximumLength) {
2767
2752
  sessionId = this._sessionIdGenerator();
2768
2753
  windowId = this._windowIdGenerator();
2769
- logger$3.info('new session ID generated', {
2754
+ logger$2.info('new session ID generated', {
2770
2755
  sessionId,
2771
2756
  windowId,
2772
2757
  changeReason: {
@@ -2955,10 +2940,10 @@ class PageViewManager {
2955
2940
  lastContentY = Math.ceil(lastContentY);
2956
2941
  maxContentY = Math.ceil(maxContentY);
2957
2942
  // if the maximum scroll height is near 0, then the percentage is 1
2958
- const lastScrollPercentage = maxScrollHeight <= 1 ? 1 : clampToRange(lastScrollY / maxScrollHeight, 0, 1, logger$3);
2959
- const maxScrollPercentage = maxScrollHeight <= 1 ? 1 : clampToRange(maxScrollY / maxScrollHeight, 0, 1, logger$3);
2960
- const lastContentPercentage = maxContentHeight <= 1 ? 1 : clampToRange(lastContentY / maxContentHeight, 0, 1, logger$3);
2961
- const maxContentPercentage = maxContentHeight <= 1 ? 1 : clampToRange(maxContentY / maxContentHeight, 0, 1, logger$3);
2943
+ const lastScrollPercentage = maxScrollHeight <= 1 ? 1 : clampToRange(lastScrollY / maxScrollHeight, 0, 1, logger$2);
2944
+ const maxScrollPercentage = maxScrollHeight <= 1 ? 1 : clampToRange(maxScrollY / maxScrollHeight, 0, 1, logger$2);
2945
+ const lastContentPercentage = maxContentHeight <= 1 ? 1 : clampToRange(lastContentY / maxContentHeight, 0, 1, logger$2);
2946
+ const maxContentPercentage = maxContentHeight <= 1 ? 1 : clampToRange(maxContentY / maxContentHeight, 0, 1, logger$2);
2962
2947
  properties = extend(properties, {
2963
2948
  $prev_pageview_last_scroll: lastScrollY,
2964
2949
  $prev_pageview_last_scroll_percentage: lastScrollPercentage,
@@ -3121,84 +3106,129 @@ const isLikelyBot = function (navigator, customBlockedUserAgents) {
3121
3106
  // It would be very bad if posthog-js caused a permission prompt to appear on every page load.
3122
3107
  };
3123
3108
 
3109
+ // Use a safe global target (prefer `win`, fallback to globalThis)
3110
+ const _target = win ?? globalThis;
3111
+ _target.__PosthogExtensions__ = _target.__PosthogExtensions__ || {};
3112
+ // Expose rrweb.record under the same contract
3113
+ _target.__PosthogExtensions__.rrweb = _target.__PosthogExtensions__.rrweb || {
3114
+ record: record
3115
+ };
3116
+ // Provide initSessionRecording if not present — return a new LazyLoadedSessionRecording when called
3117
+ _target.__PosthogExtensions__.initSessionRecording = _target.__PosthogExtensions__.initSessionRecording || (instance => {
3118
+ const factory = _target.__PosthogExtensions__._initSessionRecordingFactory;
3119
+ if (factory) {
3120
+ return factory(instance);
3121
+ }
3122
+ // If no factory is registered yet, return undefined — callers should handle lazy-loading.
3123
+ return undefined;
3124
+ });
3125
+ // Provide a no-op loadExternalDependency that calls the callback immediately (since rrweb is bundled)
3126
+ _target.__PosthogExtensions__.loadExternalDependency = _target.__PosthogExtensions__.loadExternalDependency || ((instance, scriptName, cb) => {
3127
+ if (cb) cb(undefined);
3128
+ });
3129
+ // Provide rrwebPlugins object with network plugin factory if not present
3130
+ _target.__PosthogExtensions__.rrwebPlugins = _target.__PosthogExtensions__.rrwebPlugins || {};
3131
+ // Default to undefined; the lazy-loaded recorder will register the real factory when it initializes.
3132
+ _target.__PosthogExtensions__.rrwebPlugins.getRecordNetworkPlugin = _target.__PosthogExtensions__.rrwebPlugins.getRecordNetworkPlugin || (() => undefined);
3133
+
3134
+ // Type definitions copied from @rrweb/types@2.0.0-alpha.17 and rrweb-snapshot@2.0.0-alpha.17
3135
+ // Both packages are MIT licensed: https://github.com/rrweb-io/rrweb
3136
+ //
3137
+ // These types are copied here to avoid requiring users to install peer dependencies
3138
+ // solely for TypeScript type information.
3139
+ //
3140
+ // Original sources:
3141
+ // - @rrweb/types: https://github.com/rrweb-io/rrweb/tree/main/packages/@rrweb/types
3142
+ // - rrweb-snapshot: https://github.com/rrweb-io/rrweb/tree/main/packages/rrweb-snapshot
3143
+ var NodeType;
3144
+ (function (NodeType) {
3145
+ NodeType[NodeType["Document"] = 0] = "Document";
3146
+ NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
3147
+ NodeType[NodeType["Element"] = 2] = "Element";
3148
+ NodeType[NodeType["Text"] = 3] = "Text";
3149
+ NodeType[NodeType["CDATA"] = 4] = "CDATA";
3150
+ NodeType[NodeType["Comment"] = 5] = "Comment";
3151
+ })(NodeType || (NodeType = {}));
3152
+ var EventType;
3153
+ (function (EventType) {
3154
+ EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
3155
+ EventType[EventType["Load"] = 1] = "Load";
3156
+ EventType[EventType["FullSnapshot"] = 2] = "FullSnapshot";
3157
+ EventType[EventType["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
3158
+ EventType[EventType["Meta"] = 4] = "Meta";
3159
+ EventType[EventType["Custom"] = 5] = "Custom";
3160
+ EventType[EventType["Plugin"] = 6] = "Plugin";
3161
+ })(EventType || (EventType = {}));
3162
+ var IncrementalSource;
3163
+ (function (IncrementalSource) {
3164
+ IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
3165
+ IncrementalSource[IncrementalSource["MouseMove"] = 1] = "MouseMove";
3166
+ IncrementalSource[IncrementalSource["MouseInteraction"] = 2] = "MouseInteraction";
3167
+ IncrementalSource[IncrementalSource["Scroll"] = 3] = "Scroll";
3168
+ IncrementalSource[IncrementalSource["ViewportResize"] = 4] = "ViewportResize";
3169
+ IncrementalSource[IncrementalSource["Input"] = 5] = "Input";
3170
+ IncrementalSource[IncrementalSource["TouchMove"] = 6] = "TouchMove";
3171
+ IncrementalSource[IncrementalSource["MediaInteraction"] = 7] = "MediaInteraction";
3172
+ IncrementalSource[IncrementalSource["StyleSheetRule"] = 8] = "StyleSheetRule";
3173
+ IncrementalSource[IncrementalSource["CanvasMutation"] = 9] = "CanvasMutation";
3174
+ IncrementalSource[IncrementalSource["Font"] = 10] = "Font";
3175
+ IncrementalSource[IncrementalSource["Log"] = 11] = "Log";
3176
+ IncrementalSource[IncrementalSource["Drag"] = 12] = "Drag";
3177
+ IncrementalSource[IncrementalSource["StyleDeclaration"] = 13] = "StyleDeclaration";
3178
+ IncrementalSource[IncrementalSource["Selection"] = 14] = "Selection";
3179
+ IncrementalSource[IncrementalSource["AdoptedStyleSheet"] = 15] = "AdoptedStyleSheet";
3180
+ IncrementalSource[IncrementalSource["CustomElement"] = 16] = "CustomElement";
3181
+ })(IncrementalSource || (IncrementalSource = {}));
3182
+ var MouseInteractions;
3183
+ (function (MouseInteractions) {
3184
+ MouseInteractions[MouseInteractions["MouseUp"] = 0] = "MouseUp";
3185
+ MouseInteractions[MouseInteractions["MouseDown"] = 1] = "MouseDown";
3186
+ MouseInteractions[MouseInteractions["Click"] = 2] = "Click";
3187
+ MouseInteractions[MouseInteractions["ContextMenu"] = 3] = "ContextMenu";
3188
+ MouseInteractions[MouseInteractions["DblClick"] = 4] = "DblClick";
3189
+ MouseInteractions[MouseInteractions["Focus"] = 5] = "Focus";
3190
+ MouseInteractions[MouseInteractions["Blur"] = 6] = "Blur";
3191
+ MouseInteractions[MouseInteractions["TouchStart"] = 7] = "TouchStart";
3192
+ MouseInteractions[MouseInteractions["TouchMove_Departed"] = 8] = "TouchMove_Departed";
3193
+ MouseInteractions[MouseInteractions["TouchEnd"] = 9] = "TouchEnd";
3194
+ MouseInteractions[MouseInteractions["TouchCancel"] = 10] = "TouchCancel";
3195
+ })(MouseInteractions || (MouseInteractions = {}));
3196
+ var PointerTypes;
3197
+ (function (PointerTypes) {
3198
+ PointerTypes[PointerTypes["Mouse"] = 0] = "Mouse";
3199
+ PointerTypes[PointerTypes["Pen"] = 1] = "Pen";
3200
+ PointerTypes[PointerTypes["Touch"] = 2] = "Touch";
3201
+ })(PointerTypes || (PointerTypes = {}));
3202
+ var MediaInteractions;
3203
+ (function (MediaInteractions) {
3204
+ MediaInteractions[MediaInteractions["Play"] = 0] = "Play";
3205
+ MediaInteractions[MediaInteractions["Pause"] = 1] = "Pause";
3206
+ MediaInteractions[MediaInteractions["Seeked"] = 2] = "Seeked";
3207
+ MediaInteractions[MediaInteractions["VolumeChange"] = 3] = "VolumeChange";
3208
+ MediaInteractions[MediaInteractions["RateChange"] = 4] = "RateChange";
3209
+ })(MediaInteractions || (MediaInteractions = {}));
3210
+ var CanvasContext;
3211
+ (function (CanvasContext) {
3212
+ CanvasContext[CanvasContext["2D"] = 0] = "2D";
3213
+ CanvasContext[CanvasContext["WebGL"] = 1] = "WebGL";
3214
+ CanvasContext[CanvasContext["WebGL2"] = 2] = "WebGL2";
3215
+ })(CanvasContext || (CanvasContext = {}));
3216
+
3124
3217
  const _createLogger = prefix => {
3125
3218
  return {
3126
- info: (...args) => logger$3.info(prefix, ...args),
3127
- warn: (...args) => logger$3.warn(prefix, ...args),
3128
- error: (...args) => logger$3.error(prefix, ...args),
3129
- critical: (...args) => logger$3.critical(prefix, ...args),
3219
+ info: (...args) => logger$2.info(prefix, ...args),
3220
+ warn: (...args) => logger$2.warn(prefix, ...args),
3221
+ error: (...args) => logger$2.error(prefix, ...args),
3222
+ critical: (...args) => logger$2.critical(prefix, ...args),
3130
3223
  uninitializedWarning: methodName => {
3131
- logger$3.error(prefix, `You must initialize Leanbase before calling ${methodName}`);
3224
+ logger$2.error(prefix, `You must initialize Leanbase before calling ${methodName}`);
3132
3225
  },
3133
3226
  createLogger: additionalPrefix => _createLogger(`${prefix} ${additionalPrefix}`)
3134
3227
  };
3135
3228
  };
3136
- const logger$2 = _createLogger('[Leanbase]');
3229
+ const logger$1 = _createLogger('[Leanbase]');
3137
3230
  const createLogger = _createLogger;
3138
3231
 
3139
- function patch(source, name, replacement) {
3140
- try {
3141
- if (!(name in source)) {
3142
- return () => {
3143
- //
3144
- };
3145
- }
3146
- const original = source[name];
3147
- const wrapped = replacement(original);
3148
- if (isFunction(wrapped)) {
3149
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
3150
- wrapped.prototype = wrapped.prototype || {};
3151
- Object.defineProperties(wrapped, {
3152
- __posthog_wrapped__: {
3153
- enumerable: false,
3154
- value: true
3155
- }
3156
- });
3157
- }
3158
- source[name] = wrapped;
3159
- return () => {
3160
- source[name] = original;
3161
- };
3162
- } catch {
3163
- return () => {
3164
- //
3165
- };
3166
- }
3167
- }
3168
-
3169
- function hostnameFromURL(url) {
3170
- try {
3171
- if (typeof url === 'string') {
3172
- return new URL(url).hostname;
3173
- }
3174
- if ('url' in url) {
3175
- return new URL(url.url).hostname;
3176
- }
3177
- return url.hostname;
3178
- } catch {
3179
- return null;
3180
- }
3181
- }
3182
- function isHostOnDenyList(url, options) {
3183
- const hostname = hostnameFromURL(url);
3184
- const defaultNotDenied = {
3185
- hostname,
3186
- isHostDenied: false
3187
- };
3188
- if (!options.payloadHostDenyList?.length || !hostname?.trim().length) {
3189
- return defaultNotDenied;
3190
- }
3191
- for (const deny of options.payloadHostDenyList) {
3192
- if (hostname.endsWith(deny)) {
3193
- return {
3194
- hostname,
3195
- isHostDenied: true
3196
- };
3197
- }
3198
- }
3199
- return defaultNotDenied;
3200
- }
3201
-
3202
3232
  const LOGGER_PREFIX$2 = '[SessionRecording]';
3203
3233
  const REDACTED = 'redacted';
3204
3234
  const defaultNetworkOptions = {
@@ -3270,7 +3300,7 @@ function enforcePayloadSizeLimit(payload, headers, limit, description) {
3270
3300
  // people can have arbitrarily large payloads on their site, but we don't want to ingest them
3271
3301
  const limitPayloadSize = options => {
3272
3302
  // the smallest of 1MB or the specified limit if there is one
3273
- const limit = Math.min(1000000, options.payloadSizeLimitBytes ?? 1000000);
3303
+ const limit = Math.min(1000000, options.payloadSizeLimitBytes);
3274
3304
  return data => {
3275
3305
  if (data?.requestBody) {
3276
3306
  data.requestBody = enforcePayloadSizeLimit(data.requestBody, data.requestHeaders, limit, 'Request');
@@ -3328,7 +3358,7 @@ const buildNetworkRequestOptions = (instanceConfig, remoteNetworkOptions = {}) =
3328
3358
  const enforcedCleaningFn = d => payloadLimiter(ignorePostHogPaths(removeAuthorizationHeader(d), instanceConfig.host || ''));
3329
3359
  const hasDeprecatedMaskFunction = isFunction(sessionRecordingConfig.maskNetworkRequestFn);
3330
3360
  if (hasDeprecatedMaskFunction && isFunction(sessionRecordingConfig.maskCapturedNetworkRequestFn)) {
3331
- logger$2.warn('Both `maskNetworkRequestFn` and `maskCapturedNetworkRequestFn` are defined. `maskNetworkRequestFn` will be ignored.');
3361
+ logger$1.warn('Both `maskNetworkRequestFn` and `maskCapturedNetworkRequestFn` are defined. `maskNetworkRequestFn` will be ignored.');
3332
3362
  }
3333
3363
  if (hasDeprecatedMaskFunction) {
3334
3364
  sessionRecordingConfig.maskCapturedNetworkRequestFn = data => {
@@ -3355,666 +3385,6 @@ const buildNetworkRequestOptions = (instanceConfig, remoteNetworkOptions = {}) =
3355
3385
  };
3356
3386
  };
3357
3387
 
3358
- /// <reference lib="dom" />
3359
- const logger$1 = createLogger('[Recorder]');
3360
- const isNavigationTiming = entry => entry.entryType === 'navigation';
3361
- const isResourceTiming = entry => entry.entryType === 'resource';
3362
- function findLast(array, predicate) {
3363
- const length = array.length;
3364
- for (let i = length - 1; i >= 0; i -= 1) {
3365
- if (predicate(array[i])) {
3366
- return array[i];
3367
- }
3368
- }
3369
- return undefined;
3370
- }
3371
- function isDocument(value) {
3372
- return !!value && typeof value === 'object' && 'nodeType' in value && value.nodeType === 9;
3373
- }
3374
- function initPerformanceObserver(cb, win, options) {
3375
- // if we are only observing timings then we could have a single observer for all types, with buffer true,
3376
- // but we are going to filter by initiatorType _if we are wrapping fetch and xhr as the wrapped functions
3377
- // will deal with those.
3378
- // so we have a block which captures requests from before fetch/xhr is wrapped
3379
- // these are marked `isInitial` so playback can display them differently if needed
3380
- // they will never have method/status/headers/body because they are pre-wrapping that provides that
3381
- if (options.recordInitialRequests) {
3382
- const initialPerformanceEntries = win.performance.getEntries().filter(entry => isNavigationTiming(entry) || isResourceTiming(entry) && options.initiatorTypes.includes(entry.initiatorType));
3383
- cb({
3384
- requests: initialPerformanceEntries.flatMap(entry => prepareRequest({
3385
- entry,
3386
- method: undefined,
3387
- status: undefined,
3388
- networkRequest: {},
3389
- isInitial: true
3390
- })),
3391
- isInitial: true
3392
- });
3393
- }
3394
- const observer = new win.PerformanceObserver(entries => {
3395
- // if recordBody or recordHeaders is true then we don't want to record fetch or xhr here
3396
- // as the wrapped functions will do that. Otherwise, this filter becomes a noop
3397
- // because we do want to record them here
3398
- const wrappedInitiatorFilter = entry => options.recordBody || options.recordHeaders ? entry.initiatorType !== 'xmlhttprequest' && entry.initiatorType !== 'fetch' : true;
3399
- const performanceEntries = entries.getEntries().filter(entry => isNavigationTiming(entry) || isResourceTiming(entry) && options.initiatorTypes.includes(entry.initiatorType) &&
3400
- // TODO if we are _only_ capturing timing we don't want to filter initiator here
3401
- wrappedInitiatorFilter(entry));
3402
- cb({
3403
- requests: performanceEntries.flatMap(entry => prepareRequest({
3404
- entry,
3405
- method: undefined,
3406
- status: undefined,
3407
- networkRequest: {}
3408
- }))
3409
- });
3410
- });
3411
- // compat checked earlier
3412
- // eslint-disable-next-line compat/compat
3413
- const entryTypes = PerformanceObserver.supportedEntryTypes.filter(x => options.performanceEntryTypeToObserve.includes(x));
3414
- // initial records are gathered above, so we don't need to observe and buffer each type separately
3415
- observer.observe({
3416
- entryTypes
3417
- });
3418
- return () => {
3419
- observer.disconnect();
3420
- };
3421
- }
3422
- function shouldRecordHeaders(type, recordHeaders) {
3423
- return !!recordHeaders && (isBoolean(recordHeaders) || recordHeaders[type]);
3424
- }
3425
- function shouldRecordBody({
3426
- type,
3427
- recordBody,
3428
- headers,
3429
- url
3430
- }) {
3431
- function matchesContentType(contentTypes) {
3432
- const contentTypeHeader = Object.keys(headers).find(key => key.toLowerCase() === 'content-type');
3433
- const contentType = contentTypeHeader && headers[contentTypeHeader];
3434
- return contentTypes.some(ct => contentType?.includes(ct));
3435
- }
3436
- /**
3437
- * particularly in canvas applications we see many requests to blob URLs
3438
- * e.g. blob:https://video_url
3439
- * these blob/object URLs are local to the browser, we can never capture that body
3440
- * so we can just return false here
3441
- */
3442
- function isBlobURL(url) {
3443
- try {
3444
- if (typeof url === 'string') {
3445
- return url.startsWith('blob:');
3446
- }
3447
- if (url instanceof URL) {
3448
- return url.protocol === 'blob:';
3449
- }
3450
- if (url instanceof Request) {
3451
- return isBlobURL(url.url);
3452
- }
3453
- return false;
3454
- } catch {
3455
- return false;
3456
- }
3457
- }
3458
- if (!recordBody) return false;
3459
- if (isBlobURL(url)) return false;
3460
- if (isBoolean(recordBody)) return true;
3461
- if (isArray(recordBody)) return matchesContentType(recordBody);
3462
- const recordBodyType = recordBody[type];
3463
- if (isBoolean(recordBodyType)) return recordBodyType;
3464
- return matchesContentType(recordBodyType);
3465
- }
3466
- async function getRequestPerformanceEntry(win, initiatorType, url, start, end, attempt = 0) {
3467
- if (attempt > 10) {
3468
- logger$1.warn('Failed to get performance entry for request', {
3469
- url,
3470
- initiatorType
3471
- });
3472
- return null;
3473
- }
3474
- const urlPerformanceEntries = win.performance.getEntriesByName(url);
3475
- const performanceEntry = findLast(urlPerformanceEntries, entry => isResourceTiming(entry) && entry.initiatorType === initiatorType && (isUndefined(start) || entry.startTime >= start) && (isUndefined(end) || entry.startTime <= end));
3476
- if (!performanceEntry) {
3477
- await new Promise(resolve => setTimeout(resolve, 50 * attempt));
3478
- return getRequestPerformanceEntry(win, initiatorType, url, start, end, attempt + 1);
3479
- }
3480
- return performanceEntry;
3481
- }
3482
- /**
3483
- * According to MDN https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response
3484
- * xhr response is typed as any but can be an ArrayBuffer, a Blob, a Document, a JavaScript object,
3485
- * or a string, depending on the value of XMLHttpRequest.responseType, that contains the response entity body.
3486
- *
3487
- * XHR request body is Document | XMLHttpRequestBodyInit | null | undefined
3488
- */
3489
- function _tryReadXHRBody({
3490
- body,
3491
- options,
3492
- url
3493
- }) {
3494
- if (isNullish(body)) {
3495
- return null;
3496
- }
3497
- const {
3498
- hostname,
3499
- isHostDenied
3500
- } = isHostOnDenyList(url, options);
3501
- if (isHostDenied) {
3502
- return hostname + ' is in deny list';
3503
- }
3504
- if (isString(body)) {
3505
- return body;
3506
- }
3507
- if (isDocument(body)) {
3508
- return body.textContent;
3509
- }
3510
- if (isFormData(body)) {
3511
- return formDataToQuery(body);
3512
- }
3513
- if (isObject(body)) {
3514
- try {
3515
- return JSON.stringify(body);
3516
- } catch {
3517
- return '[SessionReplay] Failed to stringify response object';
3518
- }
3519
- }
3520
- return '[SessionReplay] Cannot read body of type ' + toString.call(body);
3521
- }
3522
- function initXhrObserver(cb, win, options) {
3523
- if (!options.initiatorTypes.includes('xmlhttprequest')) {
3524
- return () => {
3525
- //
3526
- };
3527
- }
3528
- const recordRequestHeaders = shouldRecordHeaders('request', options.recordHeaders);
3529
- const recordResponseHeaders = shouldRecordHeaders('response', options.recordHeaders);
3530
- const restorePatch = patch(win.XMLHttpRequest.prototype, 'open',
3531
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3532
- // @ts-ignore
3533
- originalOpen => {
3534
- return function (method, url, async = true, username, password) {
3535
- // because this function is returned in its actual context `this` _is_ an XMLHttpRequest
3536
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3537
- // @ts-ignore
3538
- const xhr = this;
3539
- // check IE earlier than this, we only initialize if Request is present
3540
- // eslint-disable-next-line compat/compat
3541
- const req = new Request(url);
3542
- const networkRequest = {};
3543
- let start;
3544
- let end;
3545
- const requestHeaders = {};
3546
- const originalSetRequestHeader = xhr.setRequestHeader.bind(xhr);
3547
- xhr.setRequestHeader = (header, value) => {
3548
- requestHeaders[header] = value;
3549
- return originalSetRequestHeader(header, value);
3550
- };
3551
- if (recordRequestHeaders) {
3552
- networkRequest.requestHeaders = requestHeaders;
3553
- }
3554
- const originalSend = xhr.send.bind(xhr);
3555
- xhr.send = body => {
3556
- if (shouldRecordBody({
3557
- type: 'request',
3558
- headers: requestHeaders,
3559
- url,
3560
- recordBody: options.recordBody
3561
- })) {
3562
- networkRequest.requestBody = _tryReadXHRBody({
3563
- body,
3564
- options,
3565
- url
3566
- });
3567
- }
3568
- start = win.performance.now();
3569
- return originalSend(body);
3570
- };
3571
- const readyStateListener = () => {
3572
- if (xhr.readyState !== xhr.DONE) {
3573
- return;
3574
- }
3575
- // Clean up the listener immediately when done to prevent memory leaks
3576
- xhr.removeEventListener('readystatechange', readyStateListener);
3577
- end = win.performance.now();
3578
- const responseHeaders = {};
3579
- const rawHeaders = xhr.getAllResponseHeaders();
3580
- const headers = rawHeaders.trim().split(/[\r\n]+/);
3581
- headers.forEach(line => {
3582
- const parts = line.split(': ');
3583
- const header = parts.shift();
3584
- const value = parts.join(': ');
3585
- if (header) {
3586
- responseHeaders[header] = value;
3587
- }
3588
- });
3589
- if (recordResponseHeaders) {
3590
- networkRequest.responseHeaders = responseHeaders;
3591
- }
3592
- if (shouldRecordBody({
3593
- type: 'response',
3594
- headers: responseHeaders,
3595
- url,
3596
- recordBody: options.recordBody
3597
- })) {
3598
- networkRequest.responseBody = _tryReadXHRBody({
3599
- body: xhr.response,
3600
- options,
3601
- url
3602
- });
3603
- }
3604
- getRequestPerformanceEntry(win, 'xmlhttprequest', req.url, start, end).then(entry => {
3605
- const requests = prepareRequest({
3606
- entry,
3607
- method: method,
3608
- status: xhr?.status,
3609
- networkRequest,
3610
- start,
3611
- end,
3612
- url: url.toString(),
3613
- initiatorType: 'xmlhttprequest'
3614
- });
3615
- cb({
3616
- requests
3617
- });
3618
- }).catch(() => {
3619
- //
3620
- });
3621
- };
3622
- // This is very tricky code, and making it passive won't bring many performance benefits,
3623
- // so let's ignore the rule here.
3624
- // eslint-disable-next-line posthog-js/no-add-event-listener
3625
- xhr.addEventListener('readystatechange', readyStateListener);
3626
- originalOpen.call(xhr, method, url, async, username, password);
3627
- };
3628
- });
3629
- return () => {
3630
- restorePatch();
3631
- };
3632
- }
3633
- /**
3634
- * Check if this PerformanceEntry is either a PerformanceResourceTiming or a PerformanceNavigationTiming
3635
- * NB PerformanceNavigationTiming extends PerformanceResourceTiming
3636
- * Here we don't care which interface it implements as both expose `serverTimings`
3637
- */
3638
- const exposesServerTiming = event => !isNull(event) && (event.entryType === 'navigation' || event.entryType === 'resource');
3639
- function prepareRequest({
3640
- entry,
3641
- method,
3642
- status,
3643
- networkRequest,
3644
- isInitial,
3645
- start,
3646
- end,
3647
- url,
3648
- initiatorType
3649
- }) {
3650
- start = entry ? entry.startTime : start;
3651
- end = entry ? entry.responseEnd : end;
3652
- // kudos to sentry javascript sdk for excellent background on why to use Date.now() here
3653
- // https://github.com/getsentry/sentry-javascript/blob/e856e40b6e71a73252e788cd42b5260f81c9c88e/packages/utils/src/time.ts#L70
3654
- // can't start observer if performance.now() is not available
3655
- // eslint-disable-next-line compat/compat
3656
- const timeOrigin = Math.floor(Date.now() - performance.now());
3657
- // clickhouse can't ingest timestamps that are floats
3658
- // (in this case representing fractions of a millisecond we don't care about anyway)
3659
- // use timeOrigin if we really can't gather a start time
3660
- const timestamp = Math.floor(timeOrigin + (start || 0));
3661
- const entryJSON = entry ? entry.toJSON() : {
3662
- name: url
3663
- };
3664
- const requests = [{
3665
- ...entryJSON,
3666
- startTime: isUndefined(start) ? undefined : Math.round(start),
3667
- endTime: isUndefined(end) ? undefined : Math.round(end),
3668
- timeOrigin,
3669
- timestamp,
3670
- method: method,
3671
- initiatorType: initiatorType ? initiatorType : entry ? entry.initiatorType : undefined,
3672
- status,
3673
- requestHeaders: networkRequest.requestHeaders,
3674
- requestBody: networkRequest.requestBody,
3675
- responseHeaders: networkRequest.responseHeaders,
3676
- responseBody: networkRequest.responseBody,
3677
- isInitial
3678
- }];
3679
- if (exposesServerTiming(entry)) {
3680
- for (const timing of entry.serverTiming || []) {
3681
- requests.push({
3682
- timeOrigin,
3683
- timestamp,
3684
- startTime: Math.round(entry.startTime),
3685
- name: timing.name,
3686
- duration: timing.duration,
3687
- // the spec has a closed list of possible types
3688
- // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry/entryType
3689
- // but, we need to know this was a server timing so that we know to
3690
- // match it to the appropriate navigation or resource timing
3691
- // that matching will have to be on timestamp and $current_url
3692
- entryType: 'serverTiming'
3693
- });
3694
- }
3695
- }
3696
- return requests;
3697
- }
3698
- const contentTypePrefixDenyList = ['video/', 'audio/'];
3699
- function _checkForCannotReadResponseBody({
3700
- r,
3701
- options,
3702
- url
3703
- }) {
3704
- if (r.headers.get('Transfer-Encoding') === 'chunked') {
3705
- return 'Chunked Transfer-Encoding is not supported';
3706
- }
3707
- // `get` and `has` are case-insensitive
3708
- // but return the header value with the casing that was supplied
3709
- const contentType = r.headers.get('Content-Type')?.toLowerCase();
3710
- const contentTypeIsDenied = contentTypePrefixDenyList.some(prefix => contentType?.startsWith(prefix));
3711
- if (contentType && contentTypeIsDenied) {
3712
- return `Content-Type ${contentType} is not supported`;
3713
- }
3714
- const {
3715
- hostname,
3716
- isHostDenied
3717
- } = isHostOnDenyList(url, options);
3718
- if (isHostDenied) {
3719
- return hostname + ' is in deny list';
3720
- }
3721
- return null;
3722
- }
3723
- function _tryReadBody(r) {
3724
- // there are now already multiple places where we're using Promise...
3725
- // eslint-disable-next-line compat/compat
3726
- return new Promise((resolve, reject) => {
3727
- const timeout = setTimeout(() => resolve('[SessionReplay] Timeout while trying to read body'), 500);
3728
- try {
3729
- r.clone().text().then(txt => resolve(txt), reason => reject(reason)).finally(() => clearTimeout(timeout));
3730
- } catch {
3731
- clearTimeout(timeout);
3732
- resolve('[SessionReplay] Failed to read body');
3733
- }
3734
- });
3735
- }
3736
- async function _tryReadRequestBody({
3737
- r,
3738
- options,
3739
- url
3740
- }) {
3741
- const {
3742
- hostname,
3743
- isHostDenied
3744
- } = isHostOnDenyList(url, options);
3745
- if (isHostDenied) {
3746
- return Promise.resolve(hostname + ' is in deny list');
3747
- }
3748
- return _tryReadBody(r);
3749
- }
3750
- async function _tryReadResponseBody({
3751
- r,
3752
- options,
3753
- url
3754
- }) {
3755
- const cannotReadBodyReason = _checkForCannotReadResponseBody({
3756
- r,
3757
- options,
3758
- url
3759
- });
3760
- if (!isNull(cannotReadBodyReason)) {
3761
- return Promise.resolve(cannotReadBodyReason);
3762
- }
3763
- return _tryReadBody(r);
3764
- }
3765
- function initFetchObserver(cb, win, options) {
3766
- if (!options.initiatorTypes.includes('fetch')) {
3767
- return () => {
3768
- //
3769
- };
3770
- }
3771
- const recordRequestHeaders = shouldRecordHeaders('request', options.recordHeaders);
3772
- const recordResponseHeaders = shouldRecordHeaders('response', options.recordHeaders);
3773
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3774
- // @ts-ignore
3775
- const restorePatch = patch(win, 'fetch', originalFetch => {
3776
- return async function (url, init) {
3777
- // check IE earlier than this, we only initialize if Request is present
3778
- // eslint-disable-next-line compat/compat
3779
- const req = new Request(url, init);
3780
- let res;
3781
- const networkRequest = {};
3782
- let start;
3783
- let end;
3784
- try {
3785
- const requestHeaders = {};
3786
- req.headers.forEach((value, header) => {
3787
- requestHeaders[header] = value;
3788
- });
3789
- if (recordRequestHeaders) {
3790
- networkRequest.requestHeaders = requestHeaders;
3791
- }
3792
- if (shouldRecordBody({
3793
- type: 'request',
3794
- headers: requestHeaders,
3795
- url,
3796
- recordBody: options.recordBody
3797
- })) {
3798
- networkRequest.requestBody = await _tryReadRequestBody({
3799
- r: req,
3800
- options,
3801
- url
3802
- });
3803
- }
3804
- start = win.performance.now();
3805
- res = await originalFetch(req);
3806
- end = win.performance.now();
3807
- const responseHeaders = {};
3808
- res.headers.forEach((value, header) => {
3809
- responseHeaders[header] = value;
3810
- });
3811
- if (recordResponseHeaders) {
3812
- networkRequest.responseHeaders = responseHeaders;
3813
- }
3814
- if (shouldRecordBody({
3815
- type: 'response',
3816
- headers: responseHeaders,
3817
- url,
3818
- recordBody: options.recordBody
3819
- })) {
3820
- networkRequest.responseBody = await _tryReadResponseBody({
3821
- r: res,
3822
- options,
3823
- url
3824
- });
3825
- }
3826
- return res;
3827
- } finally {
3828
- getRequestPerformanceEntry(win, 'fetch', req.url, start, end).then(entry => {
3829
- const requests = prepareRequest({
3830
- entry,
3831
- method: req.method,
3832
- status: res?.status,
3833
- networkRequest,
3834
- start,
3835
- end,
3836
- url: req.url,
3837
- initiatorType: 'fetch'
3838
- });
3839
- cb({
3840
- requests
3841
- });
3842
- }).catch(() => {
3843
- //
3844
- });
3845
- }
3846
- };
3847
- });
3848
- return () => {
3849
- restorePatch();
3850
- };
3851
- }
3852
- let initialisedHandler = null;
3853
- function initNetworkObserver(callback, win,
3854
- // top window or in an iframe
3855
- options) {
3856
- if (!('performance' in win)) {
3857
- return () => {
3858
- //
3859
- };
3860
- }
3861
- if (initialisedHandler) {
3862
- logger$1.warn('Network observer already initialised, doing nothing');
3863
- return () => {
3864
- // the first caller should already have this handler and will be responsible for teardown
3865
- };
3866
- }
3867
- const networkOptions = options ? Object.assign({}, defaultNetworkOptions, options) : defaultNetworkOptions;
3868
- const cb = data => {
3869
- const requests = [];
3870
- data.requests.forEach(request => {
3871
- const maskedRequest = networkOptions.maskRequestFn(request);
3872
- if (maskedRequest) {
3873
- requests.push(maskedRequest);
3874
- }
3875
- });
3876
- if (requests.length > 0) {
3877
- callback({
3878
- ...data,
3879
- requests
3880
- });
3881
- }
3882
- };
3883
- const performanceObserver = initPerformanceObserver(cb, win, networkOptions);
3884
- // only wrap fetch and xhr if headers or body are being recorded
3885
- let xhrObserver = () => {};
3886
- let fetchObserver = () => {};
3887
- if (networkOptions.recordHeaders || networkOptions.recordBody) {
3888
- xhrObserver = initXhrObserver(cb, win, networkOptions);
3889
- fetchObserver = initFetchObserver(cb, win, networkOptions);
3890
- }
3891
- const teardown = () => {
3892
- performanceObserver();
3893
- xhrObserver();
3894
- fetchObserver();
3895
- // allow future observers to initialize after cleanup
3896
- initialisedHandler = null;
3897
- };
3898
- initialisedHandler = teardown;
3899
- return teardown;
3900
- }
3901
- // use the plugin name so that when this functionality is adopted into rrweb
3902
- // we can remove this plugin and use the core functionality with the same data
3903
- const NETWORK_PLUGIN_NAME = 'rrweb/network@1';
3904
- // TODO how should this be typed?
3905
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
3906
- // @ts-ignore
3907
- const getRecordNetworkPlugin = options => {
3908
- return {
3909
- name: NETWORK_PLUGIN_NAME,
3910
- observer: initNetworkObserver,
3911
- options: options
3912
- };
3913
- };
3914
- // rrweb/networ@1 ends
3915
-
3916
- // Use a safe global target (prefer `win`, fallback to globalThis)
3917
- const _target = win ?? globalThis;
3918
- _target.__PosthogExtensions__ = _target.__PosthogExtensions__ || {};
3919
- // Expose rrweb.record under the same contract
3920
- _target.__PosthogExtensions__.rrweb = _target.__PosthogExtensions__.rrweb || {
3921
- record: record
3922
- };
3923
- // Provide initSessionRecording if not present — return a new LazyLoadedSessionRecording when called
3924
- _target.__PosthogExtensions__.initSessionRecording = _target.__PosthogExtensions__.initSessionRecording || (instance => {
3925
- return new LazyLoadedSessionRecording(instance);
3926
- });
3927
- // Provide a no-op loadExternalDependency that calls the callback immediately (since rrweb is bundled)
3928
- _target.__PosthogExtensions__.loadExternalDependency = _target.__PosthogExtensions__.loadExternalDependency || ((instance, scriptName, cb) => {
3929
- if (cb) cb(undefined);
3930
- });
3931
- // Provide rrwebPlugins object with network plugin factory if not present
3932
- _target.__PosthogExtensions__.rrwebPlugins = _target.__PosthogExtensions__.rrwebPlugins || {};
3933
- _target.__PosthogExtensions__.rrwebPlugins.getRecordNetworkPlugin = _target.__PosthogExtensions__.rrwebPlugins.getRecordNetworkPlugin || (() => getRecordNetworkPlugin);
3934
-
3935
- // Type definitions copied from @rrweb/types@2.0.0-alpha.17 and rrweb-snapshot@2.0.0-alpha.17
3936
- // Both packages are MIT licensed: https://github.com/rrweb-io/rrweb
3937
- //
3938
- // These types are copied here to avoid requiring users to install peer dependencies
3939
- // solely for TypeScript type information.
3940
- //
3941
- // Original sources:
3942
- // - @rrweb/types: https://github.com/rrweb-io/rrweb/tree/main/packages/@rrweb/types
3943
- // - rrweb-snapshot: https://github.com/rrweb-io/rrweb/tree/main/packages/rrweb-snapshot
3944
- var NodeType;
3945
- (function (NodeType) {
3946
- NodeType[NodeType["Document"] = 0] = "Document";
3947
- NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
3948
- NodeType[NodeType["Element"] = 2] = "Element";
3949
- NodeType[NodeType["Text"] = 3] = "Text";
3950
- NodeType[NodeType["CDATA"] = 4] = "CDATA";
3951
- NodeType[NodeType["Comment"] = 5] = "Comment";
3952
- })(NodeType || (NodeType = {}));
3953
- var EventType;
3954
- (function (EventType) {
3955
- EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
3956
- EventType[EventType["Load"] = 1] = "Load";
3957
- EventType[EventType["FullSnapshot"] = 2] = "FullSnapshot";
3958
- EventType[EventType["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
3959
- EventType[EventType["Meta"] = 4] = "Meta";
3960
- EventType[EventType["Custom"] = 5] = "Custom";
3961
- EventType[EventType["Plugin"] = 6] = "Plugin";
3962
- })(EventType || (EventType = {}));
3963
- var IncrementalSource;
3964
- (function (IncrementalSource) {
3965
- IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
3966
- IncrementalSource[IncrementalSource["MouseMove"] = 1] = "MouseMove";
3967
- IncrementalSource[IncrementalSource["MouseInteraction"] = 2] = "MouseInteraction";
3968
- IncrementalSource[IncrementalSource["Scroll"] = 3] = "Scroll";
3969
- IncrementalSource[IncrementalSource["ViewportResize"] = 4] = "ViewportResize";
3970
- IncrementalSource[IncrementalSource["Input"] = 5] = "Input";
3971
- IncrementalSource[IncrementalSource["TouchMove"] = 6] = "TouchMove";
3972
- IncrementalSource[IncrementalSource["MediaInteraction"] = 7] = "MediaInteraction";
3973
- IncrementalSource[IncrementalSource["StyleSheetRule"] = 8] = "StyleSheetRule";
3974
- IncrementalSource[IncrementalSource["CanvasMutation"] = 9] = "CanvasMutation";
3975
- IncrementalSource[IncrementalSource["Font"] = 10] = "Font";
3976
- IncrementalSource[IncrementalSource["Log"] = 11] = "Log";
3977
- IncrementalSource[IncrementalSource["Drag"] = 12] = "Drag";
3978
- IncrementalSource[IncrementalSource["StyleDeclaration"] = 13] = "StyleDeclaration";
3979
- IncrementalSource[IncrementalSource["Selection"] = 14] = "Selection";
3980
- IncrementalSource[IncrementalSource["AdoptedStyleSheet"] = 15] = "AdoptedStyleSheet";
3981
- IncrementalSource[IncrementalSource["CustomElement"] = 16] = "CustomElement";
3982
- })(IncrementalSource || (IncrementalSource = {}));
3983
- var MouseInteractions;
3984
- (function (MouseInteractions) {
3985
- MouseInteractions[MouseInteractions["MouseUp"] = 0] = "MouseUp";
3986
- MouseInteractions[MouseInteractions["MouseDown"] = 1] = "MouseDown";
3987
- MouseInteractions[MouseInteractions["Click"] = 2] = "Click";
3988
- MouseInteractions[MouseInteractions["ContextMenu"] = 3] = "ContextMenu";
3989
- MouseInteractions[MouseInteractions["DblClick"] = 4] = "DblClick";
3990
- MouseInteractions[MouseInteractions["Focus"] = 5] = "Focus";
3991
- MouseInteractions[MouseInteractions["Blur"] = 6] = "Blur";
3992
- MouseInteractions[MouseInteractions["TouchStart"] = 7] = "TouchStart";
3993
- MouseInteractions[MouseInteractions["TouchMove_Departed"] = 8] = "TouchMove_Departed";
3994
- MouseInteractions[MouseInteractions["TouchEnd"] = 9] = "TouchEnd";
3995
- MouseInteractions[MouseInteractions["TouchCancel"] = 10] = "TouchCancel";
3996
- })(MouseInteractions || (MouseInteractions = {}));
3997
- var PointerTypes;
3998
- (function (PointerTypes) {
3999
- PointerTypes[PointerTypes["Mouse"] = 0] = "Mouse";
4000
- PointerTypes[PointerTypes["Pen"] = 1] = "Pen";
4001
- PointerTypes[PointerTypes["Touch"] = 2] = "Touch";
4002
- })(PointerTypes || (PointerTypes = {}));
4003
- var MediaInteractions;
4004
- (function (MediaInteractions) {
4005
- MediaInteractions[MediaInteractions["Play"] = 0] = "Play";
4006
- MediaInteractions[MediaInteractions["Pause"] = 1] = "Pause";
4007
- MediaInteractions[MediaInteractions["Seeked"] = 2] = "Seeked";
4008
- MediaInteractions[MediaInteractions["VolumeChange"] = 3] = "VolumeChange";
4009
- MediaInteractions[MediaInteractions["RateChange"] = 4] = "RateChange";
4010
- })(MediaInteractions || (MediaInteractions = {}));
4011
- var CanvasContext;
4012
- (function (CanvasContext) {
4013
- CanvasContext[CanvasContext["2D"] = 0] = "2D";
4014
- CanvasContext[CanvasContext["WebGL"] = 1] = "WebGL";
4015
- CanvasContext[CanvasContext["WebGL2"] = 2] = "WebGL2";
4016
- })(CanvasContext || (CanvasContext = {}));
4017
-
4018
3388
  const DISABLED = 'disabled';
4019
3389
  const SAMPLED = 'sampled';
4020
3390
  const ACTIVE = 'active';
@@ -4422,7 +3792,7 @@ class MutationThrottler {
4422
3792
  refillInterval: 1000,
4423
3793
  // one second
4424
3794
  _onBucketRateLimited: this._onNodeRateLimited,
4425
- _logger: logger$2
3795
+ _logger: logger$1
4426
3796
  });
4427
3797
  }
4428
3798
  reset() {
@@ -4446,9 +3816,10 @@ function simpleHash(str) {
4446
3816
  * receives percent as a number between 0 and 1
4447
3817
  */
4448
3818
  function sampleOnProperty(prop, percent) {
4449
- return simpleHash(prop) % 100 < clampToRange(percent * 100, 0, 100, logger$2);
3819
+ return simpleHash(prop) % 100 < clampToRange(percent * 100, 0, 100, logger$1);
4450
3820
  }
4451
3821
 
3822
+ /* eslint-disable posthog-js/no-direct-function-check */
4452
3823
  const BASE_ENDPOINT = '/s/';
4453
3824
  const DEFAULT_CANVAS_QUALITY = 0.4;
4454
3825
  const DEFAULT_CANVAS_FPS = 4;
@@ -4459,6 +3830,19 @@ const ONE_KB = 1024;
4459
3830
  const ONE_MINUTE = 1000 * 60;
4460
3831
  const FIVE_MINUTES = ONE_MINUTE * 5;
4461
3832
  const RECORDING_IDLE_THRESHOLD_MS = FIVE_MINUTES;
3833
+ // Register a factory on the global extensions object so the extension shim can
3834
+ // instantiate a LazyLoadedSessionRecording without importing this module directly.
3835
+ try {
3836
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3837
+ const ext = globalThis.__PosthogExtensions__;
3838
+ if (ext) {
3839
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3840
+ ext._initSessionRecordingFactory = ext._initSessionRecordingFactory || (instance => new LazyLoadedSessionRecording(instance));
3841
+ }
3842
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3843
+ } catch (e) {
3844
+ // ignore
3845
+ }
4462
3846
  const RECORDING_MAX_EVENT_SIZE = ONE_KB * ONE_KB * 0.9; // ~1mb (with some wiggle room)
4463
3847
  const RECORDING_BUFFER_TIMEOUT = 2000; // 2 seconds
4464
3848
  const SESSION_RECORDING_BATCH_KEY = 'recordings';
@@ -4737,7 +4121,13 @@ class LazyLoadedSessionRecording {
4737
4121
  if (this._networkPayloadCapture) {
4738
4122
  const canRecordNetwork = !isLocalhost() || this._forceAllowLocalhostNetworkCapture;
4739
4123
  if (canRecordNetwork) {
4740
- plugins.push(getRecordNetworkPlugin(buildNetworkRequestOptions(this._instance.config, this._networkPayloadCapture)));
4124
+ const assignableWindow = globalThis;
4125
+ const networkFactory = assignableWindow.__PosthogExtensions__?.rrwebPlugins?.getRecordNetworkPlugin?.();
4126
+ if (typeof networkFactory === 'function') {
4127
+ plugins.push(networkFactory(buildNetworkRequestOptions(this._instance.config, this._networkPayloadCapture)));
4128
+ } else {
4129
+ logger.info('Network plugin factory not available yet; skipping network plugin');
4130
+ }
4741
4131
  } else {
4742
4132
  logger.info('NetworkCapture not started because we are on localhost.');
4743
4133
  }
@@ -5487,9 +4877,9 @@ class LazyLoadedSessionRecording {
5487
4877
 
5488
4878
  const LOGGER_PREFIX = '[SessionRecording]';
5489
4879
  const log = {
5490
- info: (...args) => logger$3.info(LOGGER_PREFIX, ...args),
5491
- warn: (...args) => logger$3.warn(LOGGER_PREFIX, ...args),
5492
- error: (...args) => logger$3.error(LOGGER_PREFIX, ...args)
4880
+ info: (...args) => logger$2.info(LOGGER_PREFIX, ...args),
4881
+ warn: (...args) => logger$2.warn(LOGGER_PREFIX, ...args),
4882
+ error: (...args) => logger$2.error(LOGGER_PREFIX, ...args)
5493
4883
  };
5494
4884
  class SessionRecording {
5495
4885
  get started() {
@@ -5628,7 +5018,7 @@ class SessionRecording {
5628
5018
  if (this._lazyLoadedSessionRecording?.log) {
5629
5019
  this._lazyLoadedSessionRecording.log(message, level);
5630
5020
  } else {
5631
- logger$3.warn('log called before recorder was ready');
5021
+ logger$2.warn('log called before recorder was ready');
5632
5022
  }
5633
5023
  }
5634
5024
  _onScriptLoaded(startReason) {
@@ -5893,7 +5283,7 @@ class Leanbase extends PostHogCore {
5893
5283
  };
5894
5284
  properties['distinct_id'] = persistenceProps.distinct_id;
5895
5285
  if (!(isString(properties['distinct_id']) || isNumber(properties['distinct_id'])) || isEmptyString(properties['distinct_id'])) {
5896
- logger$3.error('Invalid distinct_id for replay event. This indicates a bug in your implementation');
5286
+ logger$2.error('Invalid distinct_id for replay event. This indicates a bug in your implementation');
5897
5287
  }
5898
5288
  return properties;
5899
5289
  }
@@ -5968,11 +5358,11 @@ class Leanbase extends PostHogCore {
5968
5358
  return;
5969
5359
  }
5970
5360
  if (isUndefined(event) || !isString(event)) {
5971
- logger$3.error('No event name provided to posthog.capture');
5361
+ logger$2.error('No event name provided to posthog.capture');
5972
5362
  return;
5973
5363
  }
5974
5364
  if (properties?.$current_url && !isString(properties?.$current_url)) {
5975
- logger$3.error('Invalid `$current_url` property provided to `posthog.capture`. Input must be a string. Ignoring provided value.');
5365
+ logger$2.error('Invalid `$current_url` property provided to `posthog.capture`. Input must be a string. Ignoring provided value.');
5976
5366
  delete properties?.$current_url;
5977
5367
  }
5978
5368
  this.sessionPersistence.update_search_keyword();