@multiplayer-app/session-recorder-browser 1.2.29 → 1.2.30

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.umd.js CHANGED
@@ -24317,7 +24317,7 @@ const DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE = 100000;
24317
24317
  const SESSION_RESPONSE = 'multiplayer-debug-session-response';
24318
24318
  const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
24319
24319
  const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
24320
- const PACKAGE_VERSION_EXPORT = "1.2.29" || 0;
24320
+ const PACKAGE_VERSION_EXPORT = "1.2.30" || 0;
24321
24321
  // Regex patterns for OpenTelemetry ignore URLs
24322
24322
  const OTEL_IGNORE_URLS = [
24323
24323
  // Traces endpoint
@@ -25563,91 +25563,93 @@ function _headersInitToObject(headersInit) {
25563
25563
  }
25564
25564
  return result;
25565
25565
  }
25566
- // Store original fetch
25567
- const originalFetch = window.fetch;
25568
- // Override fetch
25569
- window.fetch = async function (input,
25570
- // eslint-disable-next-line
25571
- init) {
25572
- const networkRequest = {};
25573
- // Capture request data
25574
- const inputIsRequest = typeof Request !== 'undefined' && input instanceof Request;
25575
- const safeToConstructRequest = !inputIsRequest || !input.bodyUsed;
25576
- // Only construct a new Request when it's safe (i.e., body not already used)
25577
- let requestForMetadata = null;
25578
- if (safeToConstructRequest) {
25579
- try {
25580
- requestForMetadata = new Request(input, init);
25581
- }
25582
- catch (_a) {
25583
- // If construction fails for any reason, fall back to using available data
25584
- requestForMetadata = null;
25585
- }
25586
- }
25587
- if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordRequestHeaders) {
25588
- if (requestForMetadata) {
25589
- networkRequest.requestHeaders = _headersToObject(requestForMetadata.headers);
25590
- }
25591
- else if (inputIsRequest) {
25592
- networkRequest.requestHeaders = _headersToObject(input.headers);
25593
- }
25594
- else {
25595
- networkRequest.requestHeaders = _headersInitToObject(init === null || init === void 0 ? void 0 : init.headers);
25596
- }
25597
- }
25598
- if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
25599
- // Prefer reading from the safely constructed Request; else fallback to init.body
25600
- const urlStr = inputIsRequest
25601
- ? input.url
25602
- : (typeof input === 'string' || input instanceof URL ? String(input) : '');
25603
- const candidateBody = requestForMetadata
25604
- ? requestForMetadata.body
25605
- : (inputIsRequest ? init === null || init === void 0 ? void 0 : init.body : init === null || init === void 0 ? void 0 : init.body);
25606
- if (!(0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(candidateBody)) {
25607
- const requestBody = _tryReadFetchBody({
25608
- body: candidateBody,
25609
- url: urlStr,
25610
- });
25611
- if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) &&
25612
- new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25613
- networkRequest.requestBody = requestBody;
25566
+ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
25567
+ // Store original fetch
25568
+ const originalFetch = window.fetch;
25569
+ // Override fetch
25570
+ window.fetch = async function (input,
25571
+ // eslint-disable-next-line
25572
+ init) {
25573
+ const networkRequest = {};
25574
+ // Capture request data
25575
+ const inputIsRequest = typeof Request !== 'undefined' && input instanceof Request;
25576
+ const safeToConstructRequest = !inputIsRequest || !input.bodyUsed;
25577
+ // Only construct a new Request when it's safe (i.e., body not already used)
25578
+ let requestForMetadata = null;
25579
+ if (safeToConstructRequest) {
25580
+ try {
25581
+ requestForMetadata = new Request(input, init);
25582
+ }
25583
+ catch (_a) {
25584
+ // If construction fails for any reason, fall back to using available data
25585
+ requestForMetadata = null;
25614
25586
  }
25615
25587
  }
25616
- }
25617
- try {
25618
- // Make the actual fetch request
25619
- const response = await originalFetch(input, init);
25620
- // Capture response data
25621
- if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordResponseHeaders) {
25622
- networkRequest.responseHeaders = _headersToObject(response.headers);
25588
+ if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordRequestHeaders) {
25589
+ if (requestForMetadata) {
25590
+ networkRequest.requestHeaders = _headersToObject(requestForMetadata.headers);
25591
+ }
25592
+ else if (inputIsRequest) {
25593
+ networkRequest.requestHeaders = _headersToObject(input.headers);
25594
+ }
25595
+ else {
25596
+ networkRequest.requestHeaders = _headersInitToObject(init === null || init === void 0 ? void 0 : init.headers);
25597
+ }
25623
25598
  }
25624
25599
  if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
25625
- const responseBody = await _tryReadResponseBody(response);
25626
- if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) &&
25627
- new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25628
- networkRequest.responseBody = responseBody;
25600
+ // Prefer reading from the safely constructed Request; else fallback to init.body
25601
+ const urlStr = inputIsRequest
25602
+ ? input.url
25603
+ : (typeof input === 'string' || input instanceof URL ? String(input) : '');
25604
+ const candidateBody = requestForMetadata
25605
+ ? requestForMetadata.body
25606
+ : (inputIsRequest ? init === null || init === void 0 ? void 0 : init.body : init === null || init === void 0 ? void 0 : init.body);
25607
+ if (!(0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(candidateBody)) {
25608
+ const requestBody = _tryReadFetchBody({
25609
+ body: candidateBody,
25610
+ url: urlStr,
25611
+ });
25612
+ if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) &&
25613
+ new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25614
+ networkRequest.requestBody = requestBody;
25615
+ }
25629
25616
  }
25630
25617
  }
25631
- // Attach network request data to the response for later access
25632
- // @ts-ignore
25633
- response.networkRequest = networkRequest;
25634
- return response;
25635
- }
25636
- catch (error) {
25637
- // Even if the fetch fails, we can still capture the request data
25638
- // Attach captured request data to the thrown error for downstream handling
25639
- // @ts-ignore
25640
- if (error && typeof error === 'object') {
25618
+ try {
25619
+ // Make the actual fetch request
25620
+ const response = await originalFetch(input, init);
25621
+ // Capture response data
25622
+ if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordResponseHeaders) {
25623
+ networkRequest.responseHeaders = _headersToObject(response.headers);
25624
+ }
25625
+ if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
25626
+ const responseBody = await _tryReadResponseBody(response);
25627
+ if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) &&
25628
+ new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25629
+ networkRequest.responseBody = responseBody;
25630
+ }
25631
+ }
25632
+ // Attach network request data to the response for later access
25641
25633
  // @ts-ignore
25642
- error.networkRequest = networkRequest;
25634
+ response.networkRequest = networkRequest;
25635
+ return response;
25643
25636
  }
25644
- throw error;
25645
- }
25646
- };
25647
- // Preserve the original fetch function's properties
25648
- Object.setPrototypeOf(window.fetch, originalFetch);
25649
- Object.defineProperty(window.fetch, 'name', { value: 'fetch' });
25650
- Object.defineProperty(window.fetch, 'length', { value: originalFetch.length });
25637
+ catch (error) {
25638
+ // Even if the fetch fails, we can still capture the request data
25639
+ // Attach captured request data to the thrown error for downstream handling
25640
+ // @ts-ignore
25641
+ if (error && typeof error === 'object') {
25642
+ // @ts-ignore
25643
+ error.networkRequest = networkRequest;
25644
+ }
25645
+ throw error;
25646
+ }
25647
+ };
25648
+ // Preserve the original fetch function's properties
25649
+ Object.setPrototypeOf(window.fetch, originalFetch);
25650
+ Object.defineProperty(window.fetch, 'name', { value: 'fetch' });
25651
+ Object.defineProperty(window.fetch, 'length', { value: originalFetch.length });
25652
+ }
25651
25653
 
25652
25654
 
25653
25655
  /***/ }),
@@ -26473,7 +26475,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
26473
26475
  *
26474
26476
  * This element is used to control the start/stop recording functionality in the session widget UI.
26475
26477
  *
26476
- * @returns {HTMLButtonElement} The recorder button element from the session widget.
26478
+ * @returns {HTMLButtonElement | null} The recorder button element from the session widget.
26477
26479
  */
26478
26480
  get sessionWidgetButtonElement() {
26479
26481
  return this._sessionWidget.recorderButton;
@@ -26501,10 +26503,12 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
26501
26503
  * Error message getter and setter
26502
26504
  */
26503
26505
  this._error = '';
26504
- const sessionLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_PROP_NAME, true);
26505
- const sessionIdLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_ID_PROP_NAME);
26506
- const sessionStateLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_STATE_PROP_NAME);
26507
- const sessionTypeLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_TYPE_PROP_NAME);
26506
+ // Safety: avoid accessing storage in SSR/non-browser environments
26507
+ const isBrowser = typeof window !== 'undefined';
26508
+ const sessionLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_PROP_NAME, true) : null;
26509
+ const sessionIdLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_ID_PROP_NAME) : null;
26510
+ const sessionStateLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_STATE_PROP_NAME) : null;
26511
+ const sessionTypeLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_TYPE_PROP_NAME) : null;
26508
26512
  if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.isSessionActive)(sessionLocal, sessionTypeLocal)) {
26509
26513
  this.session = sessionLocal;
26510
26514
  this.sessionId = sessionIdLocal;
@@ -26527,6 +26531,9 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
26527
26531
  * @param configs - custom configurations for session debugger
26528
26532
  */
26529
26533
  init(configs) {
26534
+ if (typeof window === 'undefined') {
26535
+ return;
26536
+ }
26530
26537
  this._configs = (0,_config__WEBPACK_IMPORTED_MODULE_4__.getSessionRecorderConfig)({ ...this._configs, ...configs });
26531
26538
  this._isInitialized = true;
26532
26539
  this._checkOperation('init');
@@ -27502,13 +27509,13 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
27502
27509
  this._isStarted = false;
27503
27510
  this._isPaused = false;
27504
27511
  this._isInitialized = false;
27505
- this._recorderPlacement = '';
27506
27512
  this._error = '';
27507
- this._initialPopoverVisible = false;
27513
+ this._recorderPlacement = '';
27508
27514
  this._finalPopoverVisible = false;
27509
- this._buttonState = _buttonStateConfigs__WEBPACK_IMPORTED_MODULE_6__.ButtonState.IDLE;
27515
+ this._initialPopoverVisible = false;
27510
27516
  this._continuousRecording = false;
27511
27517
  this._showContinuousRecording = true;
27518
+ this._buttonState = _buttonStateConfigs__WEBPACK_IMPORTED_MODULE_6__.ButtonState.IDLE;
27512
27519
  this._widgetTextOverrides = _config__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_WIDGET_TEXT_CONFIG;
27513
27520
  this.commentTextarea = null;
27514
27521
  this.dragManager = null;
@@ -27534,21 +27541,6 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
27534
27541
  }
27535
27542
  }
27536
27543
  };
27537
- this.recorderButton = document.createElement('button');
27538
- this.initialPopover = document.createElement('div');
27539
- this.finalPopover = document.createElement('div');
27540
- this.overlay = document.createElement('div');
27541
- this.toast = document.createElement('div');
27542
- this.submitSessionDialog = document.createElement('div');
27543
- this.uiManager = new _UIManager__WEBPACK_IMPORTED_MODULE_5__.UIManager(this.recorderButton, this.initialPopover, this.finalPopover, this.overlay, this.submitSessionDialog, this.toast, _config__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_WIDGET_TEXT_CONFIG, true);
27544
- this.uiManager.setRecorderButtonProps();
27545
- this.uiManager.setInitialPopoverProps();
27546
- this.uiManager.setFinalPopoverProps();
27547
- this.uiManager.setOverlayProps();
27548
- this.uiManager.setSubmitSessionDialogProps();
27549
- this.uiManager.setToastProps();
27550
- this.commentTextarea = this.finalPopover.querySelector('.mp-session-debugger-popover-textarea');
27551
- this.observeButtonDraggableMode();
27552
27544
  }
27553
27545
  updateState(state, continuousRecording) {
27554
27546
  this._continuousRecording = continuousRecording;
@@ -27619,9 +27611,32 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
27619
27611
  }
27620
27612
  });
27621
27613
  }
27614
+ initUiManager() {
27615
+ this.recorderButton = document.createElement('button');
27616
+ this.initialPopover = document.createElement('div');
27617
+ this.finalPopover = document.createElement('div');
27618
+ this.overlay = document.createElement('div');
27619
+ this.toast = document.createElement('div');
27620
+ this.submitSessionDialog = document.createElement('div');
27621
+ // Recreate UIManager with proper config
27622
+ this.uiManager = new _UIManager__WEBPACK_IMPORTED_MODULE_5__.UIManager(this.recorderButton, this.initialPopover, this.finalPopover, this.overlay, this.submitSessionDialog, this.toast, this._widgetTextOverrides, this._showContinuousRecording);
27623
+ // Re-initialize templates with new config
27624
+ this.uiManager.setRecorderButtonProps();
27625
+ this.uiManager.setInitialPopoverProps();
27626
+ this.uiManager.setFinalPopoverProps();
27627
+ this.uiManager.setOverlayProps();
27628
+ this.uiManager.setSubmitSessionDialogProps();
27629
+ this.uiManager.setToastProps();
27630
+ this.commentTextarea = this.finalPopover.querySelector('.mp-session-debugger-popover-textarea');
27631
+ this.observeButtonDraggableMode();
27632
+ }
27622
27633
  init(options) {
27623
27634
  if (this._isInitialized)
27624
27635
  return;
27636
+ // Safety guard: avoid DOM access in SSR/non-browser environments
27637
+ if (typeof document === 'undefined') {
27638
+ return;
27639
+ }
27625
27640
  this._isInitialized = true;
27626
27641
  this.showRecorderButton = options.showWidget;
27627
27642
  this._showContinuousRecording = options.showContinuousRecording;
@@ -27629,15 +27644,7 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
27629
27644
  ...this._widgetTextOverrides,
27630
27645
  ...options.widgetTextOverrides,
27631
27646
  };
27632
- // Recreate UIManager with proper config
27633
- this.uiManager = new _UIManager__WEBPACK_IMPORTED_MODULE_5__.UIManager(this.recorderButton, this.initialPopover, this.finalPopover, this.overlay, this.submitSessionDialog, this.toast, this._widgetTextOverrides, this._showContinuousRecording);
27634
- // Re-initialize templates with new config
27635
- this.uiManager.setRecorderButtonProps();
27636
- this.uiManager.setInitialPopoverProps();
27637
- this.uiManager.setFinalPopoverProps();
27638
- this.uiManager.setOverlayProps();
27639
- this.uiManager.setSubmitSessionDialogProps();
27640
- this.uiManager.setToastProps();
27647
+ this.initUiManager();
27641
27648
  const elements = [this.toast];
27642
27649
  if (options.showWidget) {
27643
27650
  elements.push(this.recorderButton, this.initialPopover, this.finalPopover, this.submitSessionDialog);
@@ -28718,20 +28725,30 @@ const isConsoleEvent = (event) => {
28718
28725
  /**
28719
28726
  * LocalStorage utility functions
28720
28727
  */
28728
+ const hasLocalStorage = typeof window !== 'undefined' && !!window.localStorage;
28721
28729
  const getStoredItem = (key, parse) => {
28722
- const item = localStorage === null || localStorage === void 0 ? void 0 : localStorage.getItem(key);
28730
+ if (!hasLocalStorage) {
28731
+ return parse ? null : null;
28732
+ }
28733
+ const item = window.localStorage.getItem(key);
28723
28734
  return parse ? (item ? JSON.parse(item) : null) : item;
28724
28735
  };
28725
28736
  const setStoredItem = (key, value) => {
28737
+ if (!hasLocalStorage) {
28738
+ return;
28739
+ }
28726
28740
  if (value === null || value === undefined) {
28727
- localStorage === null || localStorage === void 0 ? void 0 : localStorage.removeItem(key);
28741
+ window.localStorage.removeItem(key);
28728
28742
  }
28729
28743
  else {
28730
- localStorage === null || localStorage === void 0 ? void 0 : localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
28744
+ window.localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
28731
28745
  }
28732
28746
  };
28733
28747
  const removeStoredItem = (key) => {
28734
- localStorage === null || localStorage === void 0 ? void 0 : localStorage.removeItem(key);
28748
+ if (!hasLocalStorage) {
28749
+ return;
28750
+ }
28751
+ window.localStorage.removeItem(key);
28735
28752
  };
28736
28753
 
28737
28754
 
@@ -48276,12 +48293,29 @@ __webpack_require__.r(__webpack_exports__);
48276
48293
 
48277
48294
 
48278
48295
 
48279
- const SessionRecorderInstance = new _sessionRecorder__WEBPACK_IMPORTED_MODULE_3__.SessionRecorder();
48280
- // Attach the instance to the global object (window in browser)
48281
- if (typeof window !== 'undefined') {
48282
- window['__SESSION_RECORDER_LOADED'] = true;
48283
- window['SessionRecorder'] = SessionRecorderInstance;
48284
- (0,_listeners__WEBPACK_IMPORTED_MODULE_1__.setupListeners)(SessionRecorderInstance);
48296
+ // Create or reuse a single global instance, but be safe in non-browser environments
48297
+ const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
48298
+ // Prefer globalThis when available; fall back to window in browsers
48299
+ const globalObj = typeof globalThis !== 'undefined'
48300
+ ? globalThis
48301
+ : (isBrowser ? window : {});
48302
+ let SessionRecorderInstance;
48303
+ if (isBrowser) {
48304
+ // Reuse existing instance if already injected (e.g., by an extension)
48305
+ const existing = globalObj['SessionRecorder'];
48306
+ SessionRecorderInstance = existing !== null && existing !== void 0 ? existing : new _sessionRecorder__WEBPACK_IMPORTED_MODULE_3__.SessionRecorder();
48307
+ // Attach to the global object for reuse across bundles/loads
48308
+ globalObj['SessionRecorder'] = SessionRecorderInstance;
48309
+ globalObj['__SESSION_RECORDER_LOADED'] = true;
48310
+ // Ensure listeners are set up only once
48311
+ if (!globalObj['__SESSION_RECORDER_LISTENERS_SETUP__']) {
48312
+ (0,_listeners__WEBPACK_IMPORTED_MODULE_1__.setupListeners)(SessionRecorderInstance);
48313
+ globalObj['__SESSION_RECORDER_LISTENERS_SETUP__'] = true;
48314
+ }
48315
+ }
48316
+ else {
48317
+ // SSR / non-DOM environments: create an instance but don't touch globals or listeners
48318
+ SessionRecorderInstance = new _sessionRecorder__WEBPACK_IMPORTED_MODULE_3__.SessionRecorder();
48285
48319
  }
48286
48320
 
48287
48321
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SessionRecorderInstance);