@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/README.md CHANGED
@@ -339,66 +339,6 @@ activeSpan.setAttribute(SessionRecorder.ATTR_MULTIPLAYER_CONTINUOUS_SESSION_AUTO
339
339
 
340
340
  ## Session Recorder for Next.js
341
341
 
342
- To integrate the MySessionRecorder component into your Next.js application, follow these steps:
343
-
344
- - Create a new file (e.g., MySessionRecorder.js or MySessionRecorder.tsx) in your root directory or a components directory.
345
-
346
- - Import the component
347
-
348
- In the newly created file, add the following code:
349
-
350
- ```javascript
351
- 'use client' // Mark as Client Component
352
- import { useEffect } from 'react'
353
- import SessionRecorder from '@multiplayer-app/session-recorder-browser'
354
-
355
- export default function MySessionRecorder() {
356
- useEffect(() => {
357
- if (typeof window !== 'undefined') {
358
- SessionRecorder.init({
359
- version: '{YOUR_APPLICATION_VERSION}',
360
- application: '{YOUR_APPLICATION_NAME}',
361
- environment: '{YOUR_APPLICATION_ENVIRONMENT}',
362
- apiKey: '{YOUR_API_KEY}',
363
- recordCanvas: true, // Enable canvas recording
364
- masking: {
365
- maskAllInputs: true,
366
- maskInputOptions: {
367
- password: true,
368
- email: false,
369
- tel: false
370
- }
371
- }
372
- })
373
-
374
- SessionRecorder.setSessionAttributes({
375
- userId: '{userId}',
376
- userName: '{userName}'
377
- })
378
- }
379
- }, [])
380
-
381
- return null // No UI output needed
382
- }
383
- ```
384
-
385
- Replace the placeholders with the actual information.
386
-
387
- Now, you can use the MySessionRecorder component in your application by adding it to your desired page or layout file:
388
-
389
- ```javascript
390
- import MySessionRecorder from './MySessionRecorder' // Adjust the path as necessary
391
-
392
- export default function MyApp() {
393
- return (
394
- <>
395
- <MySessionRecorder />
396
- {/* Other components */}
397
- </>
398
- )
399
- }
400
- ```
401
-
402
342
  ### Next.js 15.3+ (App Router) — instrumentation-client.ts
403
343
 
404
344
  On Next.js 15.3+ you can initialize the Session Recorder as early as possible with `src/instrumentation-client.ts|js`, which runs before hydration. You can also export `onRouterTransitionStart` to observe navigation. See the official docs: [instrumentation-client.ts](https://nextjs.org/docs/app/api-reference/file-conventions/instrumentation-client).
@@ -25094,7 +25094,7 @@ const DEFAULT_MAX_HTTP_CAPTURING_PAYLOAD_SIZE = 100000;
25094
25094
  const SESSION_RESPONSE = 'multiplayer-debug-session-response';
25095
25095
  const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
25096
25096
  const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
25097
- const PACKAGE_VERSION_EXPORT = "1.2.29" || 0;
25097
+ const PACKAGE_VERSION_EXPORT = "1.2.30" || 0;
25098
25098
  // Regex patterns for OpenTelemetry ignore URLs
25099
25099
  const OTEL_IGNORE_URLS = [
25100
25100
  // Traces endpoint
@@ -26369,91 +26369,93 @@ function _headersInitToObject(headersInit) {
26369
26369
  }
26370
26370
  return result;
26371
26371
  }
26372
- // Store original fetch
26373
- const originalFetch = window.fetch;
26374
- // Override fetch
26375
- window.fetch = async function (input,
26376
- // eslint-disable-next-line
26377
- init) {
26378
- const networkRequest = {};
26379
- // Capture request data
26380
- const inputIsRequest = typeof Request !== 'undefined' && input instanceof Request;
26381
- const safeToConstructRequest = !inputIsRequest || !input.bodyUsed;
26382
- // Only construct a new Request when it's safe (i.e., body not already used)
26383
- let requestForMetadata = null;
26384
- if (safeToConstructRequest) {
26385
- try {
26386
- requestForMetadata = new Request(input, init);
26387
- }
26388
- catch (_a) {
26389
- // If construction fails for any reason, fall back to using available data
26390
- requestForMetadata = null;
26391
- }
26392
- }
26393
- if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordRequestHeaders) {
26394
- if (requestForMetadata) {
26395
- networkRequest.requestHeaders = _headersToObject(requestForMetadata.headers);
26396
- }
26397
- else if (inputIsRequest) {
26398
- networkRequest.requestHeaders = _headersToObject(input.headers);
26399
- }
26400
- else {
26401
- networkRequest.requestHeaders = _headersInitToObject(init === null || init === void 0 ? void 0 : init.headers);
26402
- }
26403
- }
26404
- if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
26405
- // Prefer reading from the safely constructed Request; else fallback to init.body
26406
- const urlStr = inputIsRequest
26407
- ? input.url
26408
- : (typeof input === 'string' || input instanceof URL ? String(input) : '');
26409
- const candidateBody = requestForMetadata
26410
- ? requestForMetadata.body
26411
- : (inputIsRequest ? init === null || init === void 0 ? void 0 : init.body : init === null || init === void 0 ? void 0 : init.body);
26412
- if (!(0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(candidateBody)) {
26413
- const requestBody = _tryReadFetchBody({
26414
- body: candidateBody,
26415
- url: urlStr,
26416
- });
26417
- if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) &&
26418
- new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
26419
- networkRequest.requestBody = requestBody;
26372
+ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
26373
+ // Store original fetch
26374
+ const originalFetch = window.fetch;
26375
+ // Override fetch
26376
+ window.fetch = async function (input,
26377
+ // eslint-disable-next-line
26378
+ init) {
26379
+ const networkRequest = {};
26380
+ // Capture request data
26381
+ const inputIsRequest = typeof Request !== 'undefined' && input instanceof Request;
26382
+ const safeToConstructRequest = !inputIsRequest || !input.bodyUsed;
26383
+ // Only construct a new Request when it's safe (i.e., body not already used)
26384
+ let requestForMetadata = null;
26385
+ if (safeToConstructRequest) {
26386
+ try {
26387
+ requestForMetadata = new Request(input, init);
26388
+ }
26389
+ catch (_a) {
26390
+ // If construction fails for any reason, fall back to using available data
26391
+ requestForMetadata = null;
26420
26392
  }
26421
26393
  }
26422
- }
26423
- try {
26424
- // Make the actual fetch request
26425
- const response = await originalFetch(input, init);
26426
- // Capture response data
26427
- if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordResponseHeaders) {
26428
- networkRequest.responseHeaders = _headersToObject(response.headers);
26394
+ if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordRequestHeaders) {
26395
+ if (requestForMetadata) {
26396
+ networkRequest.requestHeaders = _headersToObject(requestForMetadata.headers);
26397
+ }
26398
+ else if (inputIsRequest) {
26399
+ networkRequest.requestHeaders = _headersToObject(input.headers);
26400
+ }
26401
+ else {
26402
+ networkRequest.requestHeaders = _headersInitToObject(init === null || init === void 0 ? void 0 : init.headers);
26403
+ }
26429
26404
  }
26430
26405
  if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
26431
- const responseBody = await _tryReadResponseBody(response);
26432
- if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) &&
26433
- new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
26434
- networkRequest.responseBody = responseBody;
26406
+ // Prefer reading from the safely constructed Request; else fallback to init.body
26407
+ const urlStr = inputIsRequest
26408
+ ? input.url
26409
+ : (typeof input === 'string' || input instanceof URL ? String(input) : '');
26410
+ const candidateBody = requestForMetadata
26411
+ ? requestForMetadata.body
26412
+ : (inputIsRequest ? init === null || init === void 0 ? void 0 : init.body : init === null || init === void 0 ? void 0 : init.body);
26413
+ if (!(0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(candidateBody)) {
26414
+ const requestBody = _tryReadFetchBody({
26415
+ body: candidateBody,
26416
+ url: urlStr,
26417
+ });
26418
+ if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) &&
26419
+ new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
26420
+ networkRequest.requestBody = requestBody;
26421
+ }
26435
26422
  }
26436
26423
  }
26437
- // Attach network request data to the response for later access
26438
- // @ts-ignore
26439
- response.networkRequest = networkRequest;
26440
- return response;
26441
- }
26442
- catch (error) {
26443
- // Even if the fetch fails, we can still capture the request data
26444
- // Attach captured request data to the thrown error for downstream handling
26445
- // @ts-ignore
26446
- if (error && typeof error === 'object') {
26424
+ try {
26425
+ // Make the actual fetch request
26426
+ const response = await originalFetch(input, init);
26427
+ // Capture response data
26428
+ if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.recordResponseHeaders) {
26429
+ networkRequest.responseHeaders = _headersToObject(response.headers);
26430
+ }
26431
+ if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
26432
+ const responseBody = await _tryReadResponseBody(response);
26433
+ if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) &&
26434
+ new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
26435
+ networkRequest.responseBody = responseBody;
26436
+ }
26437
+ }
26438
+ // Attach network request data to the response for later access
26447
26439
  // @ts-ignore
26448
- error.networkRequest = networkRequest;
26440
+ response.networkRequest = networkRequest;
26441
+ return response;
26449
26442
  }
26450
- throw error;
26451
- }
26452
- };
26453
- // Preserve the original fetch function's properties
26454
- Object.setPrototypeOf(window.fetch, originalFetch);
26455
- Object.defineProperty(window.fetch, 'name', { value: 'fetch' });
26456
- Object.defineProperty(window.fetch, 'length', { value: originalFetch.length });
26443
+ catch (error) {
26444
+ // Even if the fetch fails, we can still capture the request data
26445
+ // Attach captured request data to the thrown error for downstream handling
26446
+ // @ts-ignore
26447
+ if (error && typeof error === 'object') {
26448
+ // @ts-ignore
26449
+ error.networkRequest = networkRequest;
26450
+ }
26451
+ throw error;
26452
+ }
26453
+ };
26454
+ // Preserve the original fetch function's properties
26455
+ Object.setPrototypeOf(window.fetch, originalFetch);
26456
+ Object.defineProperty(window.fetch, 'name', { value: 'fetch' });
26457
+ Object.defineProperty(window.fetch, 'length', { value: originalFetch.length });
26458
+ }
26457
26459
 
26458
26460
 
26459
26461
  /***/ }),
@@ -27287,7 +27289,7 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
27287
27289
  *
27288
27290
  * This element is used to control the start/stop recording functionality in the session widget UI.
27289
27291
  *
27290
- * @returns {HTMLButtonElement} The recorder button element from the session widget.
27292
+ * @returns {HTMLButtonElement | null} The recorder button element from the session widget.
27291
27293
  */
27292
27294
  get sessionWidgetButtonElement() {
27293
27295
  return this._sessionWidget.recorderButton;
@@ -27315,10 +27317,12 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
27315
27317
  * Error message getter and setter
27316
27318
  */
27317
27319
  this._error = '';
27318
- const sessionLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_PROP_NAME, true);
27319
- const sessionIdLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_ID_PROP_NAME);
27320
- const sessionStateLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_STATE_PROP_NAME);
27321
- const sessionTypeLocal = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_TYPE_PROP_NAME);
27320
+ // Safety: avoid accessing storage in SSR/non-browser environments
27321
+ const isBrowser = typeof window !== 'undefined';
27322
+ const sessionLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_PROP_NAME, true) : null;
27323
+ const sessionIdLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_ID_PROP_NAME) : null;
27324
+ const sessionStateLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_STATE_PROP_NAME) : null;
27325
+ const sessionTypeLocal = isBrowser ? (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getStoredItem)(_config__WEBPACK_IMPORTED_MODULE_4__.SESSION_TYPE_PROP_NAME) : null;
27322
27326
  if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.isSessionActive)(sessionLocal, sessionTypeLocal)) {
27323
27327
  this.session = sessionLocal;
27324
27328
  this.sessionId = sessionIdLocal;
@@ -27341,6 +27345,9 @@ class SessionRecorder extends lib0_observable__WEBPACK_IMPORTED_MODULE_14__.Obse
27341
27345
  * @param configs - custom configurations for session debugger
27342
27346
  */
27343
27347
  init(configs) {
27348
+ if (typeof window === 'undefined') {
27349
+ return;
27350
+ }
27344
27351
  this._configs = (0,_config__WEBPACK_IMPORTED_MODULE_4__.getSessionRecorderConfig)({ ...this._configs, ...configs });
27345
27352
  this._isInitialized = true;
27346
27353
  this._checkOperation('init');
@@ -28321,13 +28328,13 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
28321
28328
  this._isStarted = false;
28322
28329
  this._isPaused = false;
28323
28330
  this._isInitialized = false;
28324
- this._recorderPlacement = '';
28325
28331
  this._error = '';
28326
- this._initialPopoverVisible = false;
28332
+ this._recorderPlacement = '';
28327
28333
  this._finalPopoverVisible = false;
28328
- this._buttonState = _buttonStateConfigs__WEBPACK_IMPORTED_MODULE_6__.ButtonState.IDLE;
28334
+ this._initialPopoverVisible = false;
28329
28335
  this._continuousRecording = false;
28330
28336
  this._showContinuousRecording = true;
28337
+ this._buttonState = _buttonStateConfigs__WEBPACK_IMPORTED_MODULE_6__.ButtonState.IDLE;
28331
28338
  this._widgetTextOverrides = _config__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_WIDGET_TEXT_CONFIG;
28332
28339
  this.commentTextarea = null;
28333
28340
  this.dragManager = null;
@@ -28353,21 +28360,6 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
28353
28360
  }
28354
28361
  }
28355
28362
  };
28356
- this.recorderButton = document.createElement('button');
28357
- this.initialPopover = document.createElement('div');
28358
- this.finalPopover = document.createElement('div');
28359
- this.overlay = document.createElement('div');
28360
- this.toast = document.createElement('div');
28361
- this.submitSessionDialog = document.createElement('div');
28362
- 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);
28363
- this.uiManager.setRecorderButtonProps();
28364
- this.uiManager.setInitialPopoverProps();
28365
- this.uiManager.setFinalPopoverProps();
28366
- this.uiManager.setOverlayProps();
28367
- this.uiManager.setSubmitSessionDialogProps();
28368
- this.uiManager.setToastProps();
28369
- this.commentTextarea = this.finalPopover.querySelector('.mp-session-debugger-popover-textarea');
28370
- this.observeButtonDraggableMode();
28371
28363
  }
28372
28364
  updateState(state, continuousRecording) {
28373
28365
  this._continuousRecording = continuousRecording;
@@ -28438,9 +28430,32 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
28438
28430
  }
28439
28431
  });
28440
28432
  }
28433
+ initUiManager() {
28434
+ this.recorderButton = document.createElement('button');
28435
+ this.initialPopover = document.createElement('div');
28436
+ this.finalPopover = document.createElement('div');
28437
+ this.overlay = document.createElement('div');
28438
+ this.toast = document.createElement('div');
28439
+ this.submitSessionDialog = document.createElement('div');
28440
+ // Recreate UIManager with proper config
28441
+ 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);
28442
+ // Re-initialize templates with new config
28443
+ this.uiManager.setRecorderButtonProps();
28444
+ this.uiManager.setInitialPopoverProps();
28445
+ this.uiManager.setFinalPopoverProps();
28446
+ this.uiManager.setOverlayProps();
28447
+ this.uiManager.setSubmitSessionDialogProps();
28448
+ this.uiManager.setToastProps();
28449
+ this.commentTextarea = this.finalPopover.querySelector('.mp-session-debugger-popover-textarea');
28450
+ this.observeButtonDraggableMode();
28451
+ }
28441
28452
  init(options) {
28442
28453
  if (this._isInitialized)
28443
28454
  return;
28455
+ // Safety guard: avoid DOM access in SSR/non-browser environments
28456
+ if (typeof document === 'undefined') {
28457
+ return;
28458
+ }
28444
28459
  this._isInitialized = true;
28445
28460
  this.showRecorderButton = options.showWidget;
28446
28461
  this._showContinuousRecording = options.showContinuousRecording;
@@ -28448,15 +28463,7 @@ class SessionWidget extends lib0_observable__WEBPACK_IMPORTED_MODULE_7__.Observa
28448
28463
  ...this._widgetTextOverrides,
28449
28464
  ...options.widgetTextOverrides,
28450
28465
  };
28451
- // Recreate UIManager with proper config
28452
- 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);
28453
- // Re-initialize templates with new config
28454
- this.uiManager.setRecorderButtonProps();
28455
- this.uiManager.setInitialPopoverProps();
28456
- this.uiManager.setFinalPopoverProps();
28457
- this.uiManager.setOverlayProps();
28458
- this.uiManager.setSubmitSessionDialogProps();
28459
- this.uiManager.setToastProps();
28466
+ this.initUiManager();
28460
28467
  const elements = [this.toast];
28461
28468
  if (options.showWidget) {
28462
28469
  elements.push(this.recorderButton, this.initialPopover, this.finalPopover, this.submitSessionDialog);
@@ -29596,20 +29603,30 @@ __webpack_require__.r(__webpack_exports__);
29596
29603
  /**
29597
29604
  * LocalStorage utility functions
29598
29605
  */
29606
+ const hasLocalStorage = typeof window !== 'undefined' && !!window.localStorage;
29599
29607
  const getStoredItem = (key, parse) => {
29600
- const item = localStorage === null || localStorage === void 0 ? void 0 : localStorage.getItem(key);
29608
+ if (!hasLocalStorage) {
29609
+ return parse ? null : null;
29610
+ }
29611
+ const item = window.localStorage.getItem(key);
29601
29612
  return parse ? (item ? JSON.parse(item) : null) : item;
29602
29613
  };
29603
29614
  const setStoredItem = (key, value) => {
29615
+ if (!hasLocalStorage) {
29616
+ return;
29617
+ }
29604
29618
  if (value === null || value === undefined) {
29605
- localStorage === null || localStorage === void 0 ? void 0 : localStorage.removeItem(key);
29619
+ window.localStorage.removeItem(key);
29606
29620
  }
29607
29621
  else {
29608
- localStorage === null || localStorage === void 0 ? void 0 : localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
29622
+ window.localStorage.setItem(key, typeof value === 'string' ? value : JSON.stringify(value));
29609
29623
  }
29610
29624
  };
29611
29625
  const removeStoredItem = (key) => {
29612
- localStorage === null || localStorage === void 0 ? void 0 : localStorage.removeItem(key);
29626
+ if (!hasLocalStorage) {
29627
+ return;
29628
+ }
29629
+ window.localStorage.removeItem(key);
29613
29630
  };
29614
29631
 
29615
29632
 
@@ -49256,12 +49273,29 @@ __webpack_require__.r(__webpack_exports__);
49256
49273
 
49257
49274
 
49258
49275
 
49259
- const SessionRecorderInstance = new _sessionRecorder__WEBPACK_IMPORTED_MODULE_3__.SessionRecorder();
49260
- // Attach the instance to the global object (window in browser)
49261
- if (typeof window !== 'undefined') {
49262
- window['__SESSION_RECORDER_LOADED'] = true;
49263
- window['SessionRecorder'] = SessionRecorderInstance;
49264
- (0,_listeners__WEBPACK_IMPORTED_MODULE_1__.setupListeners)(SessionRecorderInstance);
49276
+ // Create or reuse a single global instance, but be safe in non-browser environments
49277
+ const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
49278
+ // Prefer globalThis when available; fall back to window in browsers
49279
+ const globalObj = typeof globalThis !== 'undefined'
49280
+ ? globalThis
49281
+ : (isBrowser ? window : {});
49282
+ let SessionRecorderInstance;
49283
+ if (isBrowser) {
49284
+ // Reuse existing instance if already injected (e.g., by an extension)
49285
+ const existing = globalObj['SessionRecorder'];
49286
+ SessionRecorderInstance = existing !== null && existing !== void 0 ? existing : new _sessionRecorder__WEBPACK_IMPORTED_MODULE_3__.SessionRecorder();
49287
+ // Attach to the global object for reuse across bundles/loads
49288
+ globalObj['SessionRecorder'] = SessionRecorderInstance;
49289
+ globalObj['__SESSION_RECORDER_LOADED'] = true;
49290
+ // Ensure listeners are set up only once
49291
+ if (!globalObj['__SESSION_RECORDER_LISTENERS_SETUP__']) {
49292
+ (0,_listeners__WEBPACK_IMPORTED_MODULE_1__.setupListeners)(SessionRecorderInstance);
49293
+ globalObj['__SESSION_RECORDER_LISTENERS_SETUP__'] = true;
49294
+ }
49295
+ }
49296
+ else {
49297
+ // SSR / non-DOM environments: create an instance but don't touch globals or listeners
49298
+ SessionRecorderInstance = new _sessionRecorder__WEBPACK_IMPORTED_MODULE_3__.SessionRecorder();
49265
49299
  }
49266
49300
 
49267
49301
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SessionRecorderInstance);