@multiplayer-app/session-recorder-react-native 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/lib/module/patch/fetch.js +71 -11
- package/lib/module/patch/fetch.js.map +1 -1
- package/package.json +2 -2
- package/src/patch/fetch.ts +73 -11
|
@@ -24,27 +24,87 @@ function _tryReadFetchBody({
|
|
|
24
24
|
}
|
|
25
25
|
return `[Fetch] Cannot read body of type ${Object.prototype.toString.call(body)}`;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Detects if a response is a streaming response that should NOT have its body read.
|
|
30
|
+
* Reading the body of streaming responses (SSE, chunked streams, etc.) will either:
|
|
31
|
+
* - Block forever (SSE streams never end)
|
|
32
|
+
* - Corrupt the stream for the actual consumer
|
|
33
|
+
*/
|
|
34
|
+
function _isStreamingResponse(response) {
|
|
35
|
+
const contentType = response.headers.get('content-type')?.toLowerCase() ?? '';
|
|
36
|
+
|
|
37
|
+
// SSE - Server-Sent Events (infinite stream)
|
|
38
|
+
if (contentType.includes('text/event-stream')) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Binary streams that are typically long-running
|
|
43
|
+
if (contentType.includes('application/octet-stream')) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// NDJSON streaming (newline-delimited JSON, common in streaming APIs)
|
|
48
|
+
if (contentType.includes('application/x-ndjson') || contentType.includes('application/ndjson')) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// gRPC-web streaming
|
|
53
|
+
if (contentType.includes('application/grpc')) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check for chunked transfer encoding (often indicates streaming)
|
|
58
|
+
const transferEncoding = response.headers.get('transfer-encoding')?.toLowerCase();
|
|
59
|
+
if (transferEncoding?.includes('chunked')) {
|
|
60
|
+
// Chunked alone isn't definitive, but combined with no content-length = streaming
|
|
61
|
+
const contentLength = response.headers.get('content-length');
|
|
62
|
+
if (!contentLength) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Safely reads response body for non-streaming responses.
|
|
71
|
+
* Returns null for streaming responses to avoid blocking/corruption.
|
|
72
|
+
*/
|
|
27
73
|
async function _tryReadResponseBody(response) {
|
|
74
|
+
// CRITICAL: Never attempt to read streaming response bodies
|
|
75
|
+
if (_isStreamingResponse(response)) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
28
78
|
try {
|
|
29
79
|
// Clone the response to avoid consuming the original stream.
|
|
30
80
|
const clonedResponse = response.clone();
|
|
31
|
-
const contentType = response.headers.get('content-type')
|
|
81
|
+
const contentType = response.headers.get('content-type')?.toLowerCase() ?? '';
|
|
82
|
+
|
|
83
|
+
// Check content-length to avoid reading massive responses
|
|
84
|
+
const contentLength = response.headers.get('content-length');
|
|
85
|
+
if (contentLength) {
|
|
86
|
+
const length = parseInt(contentLength, 10);
|
|
87
|
+
if (!isNaN(length) && length > configs.maxCapturingHttpPayloadSize) {
|
|
88
|
+
return `[Fetch] Response too large (${length} bytes)`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
32
91
|
if (contentType.includes('application/json')) {
|
|
33
92
|
const json = await clonedResponse.json();
|
|
34
93
|
return JSON.stringify(json);
|
|
35
|
-
}
|
|
94
|
+
}
|
|
95
|
+
if (contentType.includes('text/')) {
|
|
36
96
|
return await clonedResponse.text();
|
|
37
|
-
}
|
|
38
|
-
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// For unknown types, attempt text read
|
|
100
|
+
try {
|
|
101
|
+
return await clonedResponse.text();
|
|
102
|
+
} catch {
|
|
39
103
|
try {
|
|
40
|
-
|
|
104
|
+
const arrayBuffer = await clonedResponse.arrayBuffer();
|
|
105
|
+
return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`;
|
|
41
106
|
} catch {
|
|
42
|
-
|
|
43
|
-
const arrayBuffer = await clonedResponse.arrayBuffer();
|
|
44
|
-
return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`;
|
|
45
|
-
} catch {
|
|
46
|
-
return '[Fetch] Unable to read response body';
|
|
47
|
-
}
|
|
107
|
+
return '[Fetch] Unable to read response body';
|
|
48
108
|
}
|
|
49
109
|
}
|
|
50
110
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["isFormData","isNullish","isObject","isString","formDataToQuery","configs","_tryReadFetchBody","body","JSON","stringify","Object","prototype","toString","call","
|
|
1
|
+
{"version":3,"names":["isFormData","isNullish","isObject","isString","formDataToQuery","configs","_tryReadFetchBody","body","JSON","stringify","Object","prototype","toString","call","_isStreamingResponse","response","contentType","headers","get","toLowerCase","includes","transferEncoding","contentLength","_tryReadResponseBody","clonedResponse","clone","length","parseInt","isNaN","maxCapturingHttpPayloadSize","json","text","arrayBuffer","byteLength","error","Error","message","_headersToObject","result","forEach","value","key","_headersInitToObject","headersInit","Headers","Array","isArray","String","entries","fetch","global","originalFetch","input","init","networkRequest","inputIsRequest","Request","recordRequestHeaders","requestHeaders","shouldRecordBody","candidateBody","requestBody","Blob","size","recordResponseHeaders","responseHeaders","responseBody","setPrototypeOf","defineProperty","console","warn","info"],"sourceRoot":"../../../src","sources":["patch/fetch.ts"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplayer-app/session-recorder-react-native",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.16",
|
|
4
4
|
"description": "Multiplayer Fullstack Session Recorder for React Native",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Multiplayer Software, Inc.",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"typescript": "^5.9.2"
|
|
108
108
|
},
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"@multiplayer-app/session-recorder-common": "1.3.
|
|
110
|
+
"@multiplayer-app/session-recorder-common": "1.3.16",
|
|
111
111
|
"@opentelemetry/core": "2.0.1",
|
|
112
112
|
"@opentelemetry/exporter-trace-otlp-http": "0.203.0",
|
|
113
113
|
"@opentelemetry/instrumentation": "0.203.0",
|
package/src/patch/fetch.ts
CHANGED
|
@@ -35,28 +35,90 @@ function _tryReadFetchBody({
|
|
|
35
35
|
return `[Fetch] Cannot read body of type ${Object.prototype.toString.call(body)}`
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Detects if a response is a streaming response that should NOT have its body read.
|
|
40
|
+
* Reading the body of streaming responses (SSE, chunked streams, etc.) will either:
|
|
41
|
+
* - Block forever (SSE streams never end)
|
|
42
|
+
* - Corrupt the stream for the actual consumer
|
|
43
|
+
*/
|
|
44
|
+
function _isStreamingResponse(response: Response): boolean {
|
|
45
|
+
const contentType = response.headers.get('content-type')?.toLowerCase() ?? ''
|
|
46
|
+
|
|
47
|
+
// SSE - Server-Sent Events (infinite stream)
|
|
48
|
+
if (contentType.includes('text/event-stream')) {
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Binary streams that are typically long-running
|
|
53
|
+
if (contentType.includes('application/octet-stream')) {
|
|
54
|
+
return true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// NDJSON streaming (newline-delimited JSON, common in streaming APIs)
|
|
58
|
+
if (contentType.includes('application/x-ndjson') || contentType.includes('application/ndjson')) {
|
|
59
|
+
return true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// gRPC-web streaming
|
|
63
|
+
if (contentType.includes('application/grpc')) {
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check for chunked transfer encoding (often indicates streaming)
|
|
68
|
+
const transferEncoding = response.headers.get('transfer-encoding')?.toLowerCase()
|
|
69
|
+
if (transferEncoding?.includes('chunked')) {
|
|
70
|
+
// Chunked alone isn't definitive, but combined with no content-length = streaming
|
|
71
|
+
const contentLength = response.headers.get('content-length')
|
|
72
|
+
if (!contentLength) {
|
|
73
|
+
return true
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Safely reads response body for non-streaming responses.
|
|
82
|
+
* Returns null for streaming responses to avoid blocking/corruption.
|
|
83
|
+
*/
|
|
38
84
|
async function _tryReadResponseBody(response: Response): Promise<string | null> {
|
|
85
|
+
// CRITICAL: Never attempt to read streaming response bodies
|
|
86
|
+
if (_isStreamingResponse(response)) {
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
|
|
39
90
|
try {
|
|
40
91
|
// Clone the response to avoid consuming the original stream.
|
|
41
92
|
const clonedResponse = response.clone()
|
|
93
|
+
const contentType = response.headers.get('content-type')?.toLowerCase() ?? ''
|
|
94
|
+
|
|
95
|
+
// Check content-length to avoid reading massive responses
|
|
96
|
+
const contentLength = response.headers.get('content-length')
|
|
97
|
+
if (contentLength) {
|
|
98
|
+
const length = parseInt(contentLength, 10)
|
|
99
|
+
if (!isNaN(length) && length > configs.maxCapturingHttpPayloadSize) {
|
|
100
|
+
return `[Fetch] Response too large (${length} bytes)`
|
|
101
|
+
}
|
|
102
|
+
}
|
|
42
103
|
|
|
43
|
-
const contentType = response.headers.get('content-type') || ''
|
|
44
104
|
if (contentType.includes('application/json')) {
|
|
45
105
|
const json = await clonedResponse.json()
|
|
46
106
|
return JSON.stringify(json)
|
|
47
|
-
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (contentType.includes('text/')) {
|
|
48
110
|
return await clonedResponse.text()
|
|
49
|
-
}
|
|
50
|
-
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// For unknown types, attempt text read
|
|
114
|
+
try {
|
|
115
|
+
return await clonedResponse.text()
|
|
116
|
+
} catch {
|
|
51
117
|
try {
|
|
52
|
-
|
|
118
|
+
const arrayBuffer = await clonedResponse.arrayBuffer()
|
|
119
|
+
return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`
|
|
53
120
|
} catch {
|
|
54
|
-
|
|
55
|
-
const arrayBuffer = await clonedResponse.arrayBuffer()
|
|
56
|
-
return `[Fetch] Binary data (${arrayBuffer.byteLength} bytes)`
|
|
57
|
-
} catch {
|
|
58
|
-
return '[Fetch] Unable to read response body'
|
|
59
|
-
}
|
|
121
|
+
return '[Fetch] Unable to read response body'
|
|
60
122
|
}
|
|
61
123
|
}
|
|
62
124
|
} catch (error) {
|