@multiplayer-app/session-recorder-browser 1.3.13 → 1.3.15
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/browser/index.js +88 -40
- package/dist/exporters/index.js +1 -1
- package/dist/index.js +88 -40
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +88 -40
- package/dist/index.umd.js.map +1 -1
- package/dist/otel/index.d.ts +1 -0
- package/dist/otel/index.d.ts.map +1 -1
- package/dist/otel/index.js +14 -17
- package/dist/otel/index.js.map +1 -1
- package/dist/patch/fetch.js +74 -23
- package/dist/patch/fetch.js.map +1 -1
- package/package.json +3 -3
package/dist/browser/index.js
CHANGED
|
@@ -25051,7 +25051,7 @@ const CONTINUOUS_DEBUGGING_TIMEOUT = 60000; // 1 minutes
|
|
|
25051
25051
|
const DEBUG_SESSION_MAX_DURATION_SECONDS = 10 * 60 + 30; // TODO: move to shared config otel core
|
|
25052
25052
|
const REMOTE_SESSION_RECORDING_START = 'remote-session-recording:start';
|
|
25053
25053
|
const REMOTE_SESSION_RECORDING_STOP = 'remote-session-recording:stop';
|
|
25054
|
-
const PACKAGE_VERSION_EXPORT = "1.3.
|
|
25054
|
+
const PACKAGE_VERSION_EXPORT = "1.3.15" || 0;
|
|
25055
25055
|
// Regex patterns for OpenTelemetry ignore URLs
|
|
25056
25056
|
const OTEL_IGNORE_URLS = [
|
|
25057
25057
|
// Traces endpoint
|
|
@@ -25989,7 +25989,6 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
25989
25989
|
|
|
25990
25990
|
|
|
25991
25991
|
|
|
25992
|
-
|
|
25993
25992
|
class TracerBrowserSDK {
|
|
25994
25993
|
constructor() {
|
|
25995
25994
|
this.sessionId = '';
|
|
@@ -26164,14 +26163,7 @@ class TracerBrowserSDK {
|
|
|
26164
26163
|
try {
|
|
26165
26164
|
const activeSpan = _opentelemetry_api__WEBPACK_IMPORTED_MODULE_10__.trace.getSpan(_opentelemetry_api__WEBPACK_IMPORTED_MODULE_11__.context.active());
|
|
26166
26165
|
if (activeSpan) {
|
|
26167
|
-
|
|
26168
|
-
_multiplayer_app_session_recorder_common__WEBPACK_IMPORTED_MODULE_1__.SessionRecorderSdk.captureException(error);
|
|
26169
|
-
activeSpan.addEvent('exception', {
|
|
26170
|
-
'exception.type': error.name || 'Error',
|
|
26171
|
-
'exception.message': error.message,
|
|
26172
|
-
'exception.stacktrace': error.stack || '',
|
|
26173
|
-
...(errorInfo || {}),
|
|
26174
|
-
});
|
|
26166
|
+
this._recordException(activeSpan, error, errorInfo);
|
|
26175
26167
|
return;
|
|
26176
26168
|
}
|
|
26177
26169
|
// eslint-disable-next-line
|
|
@@ -26181,19 +26173,24 @@ class TracerBrowserSDK {
|
|
|
26181
26173
|
try {
|
|
26182
26174
|
const tracer = _opentelemetry_api__WEBPACK_IMPORTED_MODULE_10__.trace.getTracer('exception');
|
|
26183
26175
|
const span = tracer.startSpan(error.name || 'Error');
|
|
26184
|
-
|
|
26185
|
-
span.setStatus({ code: _opentelemetry_api__WEBPACK_IMPORTED_MODULE_12__.SpanStatusCode.ERROR, message: error.message });
|
|
26186
|
-
span.addEvent('exception', {
|
|
26187
|
-
'exception.type': error.name || 'Error',
|
|
26188
|
-
'exception.message': error.message,
|
|
26189
|
-
'exception.stacktrace': error.stack || '',
|
|
26190
|
-
...(errorInfo || {}),
|
|
26191
|
-
});
|
|
26176
|
+
this._recordException(span, error, errorInfo);
|
|
26192
26177
|
span.end();
|
|
26193
26178
|
// eslint-disable-next-line
|
|
26194
26179
|
}
|
|
26195
26180
|
catch (_ignored) { }
|
|
26196
26181
|
}
|
|
26182
|
+
_recordException(span, error, errorInfo) {
|
|
26183
|
+
span.recordException(error);
|
|
26184
|
+
span.setStatus({ code: _opentelemetry_api__WEBPACK_IMPORTED_MODULE_12__.SpanStatusCode.ERROR, message: error.message });
|
|
26185
|
+
span.setAttribute('exception.type', error.name || 'Error');
|
|
26186
|
+
span.setAttribute('exception.message', error.message);
|
|
26187
|
+
span.setAttribute('exception.stacktrace', error.stack || '');
|
|
26188
|
+
if (errorInfo) {
|
|
26189
|
+
Object.entries(errorInfo).forEach(([key, value]) => {
|
|
26190
|
+
span.setAttribute(`error_info.${key}`, value);
|
|
26191
|
+
});
|
|
26192
|
+
}
|
|
26193
|
+
}
|
|
26197
26194
|
_getSpanSessionIdProcessor() {
|
|
26198
26195
|
return {
|
|
26199
26196
|
forceFlush: () => Promise.resolve(),
|
|
@@ -26283,7 +26280,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
26283
26280
|
|
|
26284
26281
|
|
|
26285
26282
|
|
|
26286
|
-
function _tryReadFetchBody({ body, url
|
|
26283
|
+
function _tryReadFetchBody({ body, url }) {
|
|
26287
26284
|
if ((0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(body)) {
|
|
26288
26285
|
return null;
|
|
26289
26286
|
}
|
|
@@ -26306,32 +26303,82 @@ function _tryReadFetchBody({ body, url, }) {
|
|
|
26306
26303
|
}
|
|
26307
26304
|
return `[Fetch] Cannot read body of type ${toString.call(body)}`;
|
|
26308
26305
|
}
|
|
26306
|
+
/**
|
|
26307
|
+
* Detects if a response is a streaming response that should NOT have its body read.
|
|
26308
|
+
* Reading the body of streaming responses (SSE, chunked streams, etc.) will either:
|
|
26309
|
+
* - Block forever (SSE streams never end)
|
|
26310
|
+
* - Corrupt the stream for the actual consumer
|
|
26311
|
+
*/
|
|
26312
|
+
function _isStreamingResponse(response) {
|
|
26313
|
+
var _a, _b, _c;
|
|
26314
|
+
const contentType = (_b = (_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
|
|
26315
|
+
// SSE - Server-Sent Events (infinite stream)
|
|
26316
|
+
if (contentType.includes('text/event-stream')) {
|
|
26317
|
+
return true;
|
|
26318
|
+
}
|
|
26319
|
+
// Binary streams that are typically long-running
|
|
26320
|
+
if (contentType.includes('application/octet-stream')) {
|
|
26321
|
+
return true;
|
|
26322
|
+
}
|
|
26323
|
+
// NDJSON streaming (newline-delimited JSON, common in streaming APIs)
|
|
26324
|
+
if (contentType.includes('application/x-ndjson') || contentType.includes('application/ndjson')) {
|
|
26325
|
+
return true;
|
|
26326
|
+
}
|
|
26327
|
+
// gRPC-web streaming
|
|
26328
|
+
if (contentType.includes('application/grpc')) {
|
|
26329
|
+
return true;
|
|
26330
|
+
}
|
|
26331
|
+
// Check for chunked transfer encoding (often indicates streaming)
|
|
26332
|
+
const transferEncoding = (_c = response.headers.get('transfer-encoding')) === null || _c === void 0 ? void 0 : _c.toLowerCase();
|
|
26333
|
+
if (transferEncoding === null || transferEncoding === void 0 ? void 0 : transferEncoding.includes('chunked')) {
|
|
26334
|
+
// Chunked alone isn't definitive, but combined with no content-length = streaming
|
|
26335
|
+
const contentLength = response.headers.get('content-length');
|
|
26336
|
+
if (!contentLength) {
|
|
26337
|
+
return true;
|
|
26338
|
+
}
|
|
26339
|
+
}
|
|
26340
|
+
return false;
|
|
26341
|
+
}
|
|
26342
|
+
/**
|
|
26343
|
+
* Safely reads response body for non-streaming responses.
|
|
26344
|
+
* Returns null for streaming responses to avoid blocking/corruption.
|
|
26345
|
+
*/
|
|
26309
26346
|
async function _tryReadResponseBody(response) {
|
|
26310
26347
|
var _a, _b;
|
|
26348
|
+
// CRITICAL: Never attempt to read streaming response bodies
|
|
26349
|
+
if (_isStreamingResponse(response)) {
|
|
26350
|
+
return null;
|
|
26351
|
+
}
|
|
26311
26352
|
try {
|
|
26312
|
-
// Clone the response to avoid consuming the original
|
|
26353
|
+
// Clone the response to avoid consuming the original
|
|
26313
26354
|
const clonedResponse = response.clone();
|
|
26314
|
-
|
|
26315
|
-
|
|
26355
|
+
const contentType = (_b = (_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : '';
|
|
26356
|
+
// Check content-length to avoid reading massive responses
|
|
26357
|
+
const contentLength = response.headers.get('content-length');
|
|
26358
|
+
if (contentLength) {
|
|
26359
|
+
const length = parseInt(contentLength, 10);
|
|
26360
|
+
if (!isNaN(length) && length > _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
|
|
26361
|
+
return `[Fetch] Response too large (${length} bytes)`;
|
|
26362
|
+
}
|
|
26363
|
+
}
|
|
26364
|
+
if (contentType.includes('application/json')) {
|
|
26316
26365
|
const json = await clonedResponse.json();
|
|
26317
26366
|
return JSON.stringify(json);
|
|
26318
26367
|
}
|
|
26319
|
-
|
|
26368
|
+
if (contentType.includes('text/')) {
|
|
26320
26369
|
return await clonedResponse.text();
|
|
26321
26370
|
}
|
|
26322
|
-
|
|
26323
|
-
|
|
26371
|
+
// For unknown types, attempt text read with timeout protection
|
|
26372
|
+
try {
|
|
26373
|
+
return await clonedResponse.text();
|
|
26374
|
+
}
|
|
26375
|
+
catch (_c) {
|
|
26324
26376
|
try {
|
|
26325
|
-
|
|
26377
|
+
const arrayBuffer = await clonedResponse.arrayBuffer();
|
|
26378
|
+
return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`;
|
|
26326
26379
|
}
|
|
26327
|
-
catch (
|
|
26328
|
-
|
|
26329
|
-
const arrayBuffer = await clonedResponse.arrayBuffer();
|
|
26330
|
-
return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`;
|
|
26331
|
-
}
|
|
26332
|
-
catch (_d) {
|
|
26333
|
-
return '[Fetch] Unable to read response body';
|
|
26334
|
-
}
|
|
26380
|
+
catch (_d) {
|
|
26381
|
+
return '[Fetch] Unable to read response body';
|
|
26335
26382
|
}
|
|
26336
26383
|
}
|
|
26337
26384
|
}
|
|
@@ -26374,6 +26421,7 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
|
|
|
26374
26421
|
}
|
|
26375
26422
|
else {
|
|
26376
26423
|
// @ts-ignore
|
|
26424
|
+
;
|
|
26377
26425
|
window.fetch.__mp_session_recorder_patched__ = true;
|
|
26378
26426
|
// Store original fetch
|
|
26379
26427
|
const originalFetch = window.fetch;
|
|
@@ -26395,7 +26443,9 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
|
|
|
26395
26443
|
if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
|
|
26396
26444
|
const urlStr = inputIsRequest
|
|
26397
26445
|
? input.url
|
|
26398
|
-
:
|
|
26446
|
+
: typeof input === 'string' || input instanceof URL
|
|
26447
|
+
? String(input)
|
|
26448
|
+
: '';
|
|
26399
26449
|
// Only attempt to read the body from init (safe); avoid constructing/cloning Requests
|
|
26400
26450
|
// If the caller passed a Request as input, we do not attempt to read its body here
|
|
26401
26451
|
// eslint-disable-next-line
|
|
@@ -26403,10 +26453,9 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
|
|
|
26403
26453
|
if (!(0,_utils_type_utils__WEBPACK_IMPORTED_MODULE_0__.isNullish)(candidateBody)) {
|
|
26404
26454
|
const requestBody = _tryReadFetchBody({
|
|
26405
26455
|
body: candidateBody,
|
|
26406
|
-
url: urlStr
|
|
26456
|
+
url: urlStr
|
|
26407
26457
|
});
|
|
26408
|
-
if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) &&
|
|
26409
|
-
new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
|
|
26458
|
+
if ((requestBody === null || requestBody === void 0 ? void 0 : requestBody.length) && new Blob([requestBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
|
|
26410
26459
|
networkRequest.requestBody = requestBody;
|
|
26411
26460
|
}
|
|
26412
26461
|
}
|
|
@@ -26420,8 +26469,7 @@ if (typeof window !== 'undefined' && typeof window.fetch !== 'undefined') {
|
|
|
26420
26469
|
}
|
|
26421
26470
|
if (_configs__WEBPACK_IMPORTED_MODULE_2__.configs.shouldRecordBody) {
|
|
26422
26471
|
const responseBody = await _tryReadResponseBody(response);
|
|
26423
|
-
if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) &&
|
|
26424
|
-
new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
|
|
26472
|
+
if ((responseBody === null || responseBody === void 0 ? void 0 : responseBody.length) && new Blob([responseBody]).size <= _configs__WEBPACK_IMPORTED_MODULE_2__.configs.maxCapturingHttpPayloadSize) {
|
|
26425
26473
|
networkRequest.responseBody = responseBody;
|
|
26426
26474
|
}
|
|
26427
26475
|
}
|