@multiplayer-app/session-recorder-browser 1.3.14 → 1.3.16

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.js CHANGED
@@ -24149,7 +24149,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
24149
24149
  const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
24150
24150
  const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
24151
24151
  const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
24152
- const PACKAGE_VERSION_EXPORT = "1.3.14" || 0;
24152
+ const PACKAGE_VERSION_EXPORT = "1.3.16" || 0;
24153
24153
  // Regex patterns for OpenTelemetry ignore URLs
24154
24154
  const OTEL_IGNORE_URLS = [
24155
24155
  // Traces endpoint
@@ -25333,7 +25333,7 @@ const setShouldRecordHttpData = (shouldRecordBody, shouldRecordHeaders) => {
25333
25333
 
25334
25334
 
25335
25335
 
25336
- function _tryReadFetchBody({ body, url, }) {
25336
+ function _tryReadFetchBody({ body, url }) {
25337
25337
  if ((0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(body)) {
25338
25338
  return null;
25339
25339
  }
@@ -25356,32 +25356,82 @@ function _tryReadFetchBody({ body, url, }) {
25356
25356
  }
25357
25357
  return `[Fetch] Cannot read body of type ${toString.call(body)}`;
25358
25358
  }
25359
+ /**
25360
+ * Detects if a response is a streaming response that should NOT have its body read.
25361
+ * Reading the body of streaming responses (SSE, chunked streams, etc.) will either:
25362
+ * - Block forever (SSE streams never end)
25363
+ * - Corrupt the stream for the actual consumer
25364
+ */
25365
+ function _isStreamingResponse(response) {
25366
+ var _a, _b, _c;
25367
+ const contentType = (_b = (_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
25368
+ // SSE - Server-Sent Events (infinite stream)
25369
+ if (contentType.includes('text/event-stream')) {
25370
+ return true;
25371
+ }
25372
+ // Binary streams that are typically long-running
25373
+ if (contentType.includes('application/octet-stream')) {
25374
+ return true;
25375
+ }
25376
+ // NDJSON streaming (newline-delimited JSON, common in streaming APIs)
25377
+ if (contentType.includes('application/x-ndjson') || contentType.includes('application/ndjson')) {
25378
+ return true;
25379
+ }
25380
+ // gRPC-web streaming
25381
+ if (contentType.includes('application/grpc')) {
25382
+ return true;
25383
+ }
25384
+ // Check for chunked transfer encoding (often indicates streaming)
25385
+ const transferEncoding = (_c = response.headers.get('transfer-encoding')) === null || _c === void 0 ? void 0 : _c.toLowerCase();
25386
+ if (transferEncoding === null || transferEncoding === void 0 ? void 0 : transferEncoding.includes('chunked')) {
25387
+ // Chunked alone isn't definitive, but combined with no content-length = streaming
25388
+ const contentLength = response.headers.get('content-length');
25389
+ if (!contentLength) {
25390
+ return true;
25391
+ }
25392
+ }
25393
+ return false;
25394
+ }
25395
+ /**
25396
+ * Safely reads response body for non-streaming responses.
25397
+ * Returns null for streaming responses to avoid blocking/corruption.
25398
+ */
25359
25399
  async function _tryReadResponseBody(response) {
25360
25400
  var _a, _b;
25401
+ // CRITICAL: Never attempt to read streaming response bodies
25402
+ if (_isStreamingResponse(response)) {
25403
+ return null;
25404
+ }
25361
25405
  try {
25362
- // Clone the response to avoid consuming the original stream
25406
+ // Clone the response to avoid consuming the original
25363
25407
  const clonedResponse = response.clone();
25364
- // Try different methods to read the body
25365
- if ((_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.includes('application/json')) {
25408
+ const contentType = (_b = (_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
25409
+ // Check content-length to avoid reading massive responses
25410
+ const contentLength = response.headers.get('content-length');
25411
+ if (contentLength) {
25412
+ const length = parseInt(contentLength, 10);
25413
+ if (!isNaN(length) && length > _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25414
+ return `[Fetch] Response too large (${length} bytes)`;
25415
+ }
25416
+ }
25417
+ if (contentType.includes('application/json')) {
25366
25418
  const json = await clonedResponse.json();
25367
25419
  return JSON.stringify(json);
25368
25420
  }
25369
- else if ((_b = response.headers.get('content-type')) === null || _b === void 0 ? void 0 : _b.includes('text/')) {
25421
+ if (contentType.includes('text/')) {
25370
25422
  return await clonedResponse.text();
25371
25423
  }
25372
- else {
25373
- // For other content types, try text first, fallback to arrayBuffer
25424
+ // For unknown types, attempt text read with timeout protection
25425
+ try {
25426
+ return await clonedResponse.text();
25427
+ }
25428
+ catch (_c) {
25374
25429
  try {
25375
- return await clonedResponse.text();
25430
+ const arrayBuffer = await clonedResponse.arrayBuffer();
25431
+ return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`;
25376
25432
  }
25377
- catch (_c) {
25378
- try {
25379
- const arrayBuffer = await clonedResponse.arrayBuffer();
25380
- return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`;
25381
- }
25382
- catch (_d) {
25383
- return '[Fetch] Unable to read response body';
25384
- }
25433
+ catch (_d) {
25434
+ return '[Fetch] Unable to read response body';
25385
25435
  }
25386
25436
  }
25387
25437
  }
@@ -25424,6 +25474,7 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
25424
25474
  }
25425
25475
  else {
25426
25476
  // @ts-ignore
25477
+ ;
25427
25478
  window.fetch.__mp_session_recorder_patched__ = true;
25428
25479
  // Store original fetch
25429
25480
  const originalFetch = window.fetch;
@@ -25445,7 +25496,9 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
25445
25496
  if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
25446
25497
  const urlStr = inputIsRequest
25447
25498
  ? input.url
25448
- : (typeof input === 'string' || input instanceof URL ? String(input) : '');
25499
+ : typeof input === 'string' || input instanceof URL
25500
+ ? String(input)
25501
+ : '';
25449
25502
  // Only attempt to read the body from init (safe); avoid constructing/cloning Requests
25450
25503
  // If the caller passed a Request as input, we do not attempt to read its body here
25451
25504
  // eslint-disable-next-line
@@ -25453,10 +25506,9 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
25453
25506
  if (!(0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(candidateBody)) {
25454
25507
  const requestBody = _tryReadFetchBody({
25455
25508
  body: candidateBody,
25456
- url: urlStr,
25509
+ url: urlStr
25457
25510
  });
25458
- if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) &&
25459
- new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25511
+ if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) && new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25460
25512
  networkRequest.requestBody = requestBody;
25461
25513
  }
25462
25514
  }
@@ -25470,8 +25522,7 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
25470
25522
  }
25471
25523
  if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
25472
25524
  const responseBody = await _tryReadResponseBody(response);
25473
- if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) &&
25474
- new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25525
+ if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) && new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
25475
25526
  networkRequest.responseBody = responseBody;
25476
25527
  }
25477
25528
  }