@replayio-app-building/netlify-recorder 0.42.0 → 0.44.0
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.d.ts +18 -0
- package/dist/index.js +23 -6
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -72,6 +72,10 @@ interface NetworkCall {
|
|
|
72
72
|
responseHeaders: Record<string, string>;
|
|
73
73
|
responseBody?: string;
|
|
74
74
|
timestamp: number;
|
|
75
|
+
/** Epoch ms when the fetch call started. */
|
|
76
|
+
startTime: number;
|
|
77
|
+
/** Epoch ms when the response was received. */
|
|
78
|
+
endTime: number;
|
|
75
79
|
}
|
|
76
80
|
interface EnvRead {
|
|
77
81
|
key: string;
|
|
@@ -91,6 +95,14 @@ interface BlobData {
|
|
|
91
95
|
endTime: number;
|
|
92
96
|
/** The response returned to the client, used to detect replay mismatches. */
|
|
93
97
|
handlerResponse?: HandlerResponse$1;
|
|
98
|
+
/**
|
|
99
|
+
* The request ID of the first request handled by this module instance.
|
|
100
|
+
* When this differs from the current request's ID, the execution environment
|
|
101
|
+
* was reused (warm start) and module-level state from the original request
|
|
102
|
+
* may have affected this request's behavior (e.g. in-memory caches skipping
|
|
103
|
+
* network calls).
|
|
104
|
+
*/
|
|
105
|
+
originalRequestId?: string;
|
|
94
106
|
}
|
|
95
107
|
interface FinishRequestCallbacks {
|
|
96
108
|
/**
|
|
@@ -174,6 +186,12 @@ interface FinishRequestOptions {
|
|
|
174
186
|
* sent to the client in the `X-Replay-Request-Id` header.
|
|
175
187
|
*/
|
|
176
188
|
requestId?: string;
|
|
189
|
+
/**
|
|
190
|
+
* The request ID of the first request handled by this module instance.
|
|
191
|
+
* Included in the blob data to link warm-start requests back to the
|
|
192
|
+
* cold-start request that populated module-level caches.
|
|
193
|
+
*/
|
|
194
|
+
originalRequestId?: string;
|
|
177
195
|
}
|
|
178
196
|
/**
|
|
179
197
|
* Called at the end of the handler execution.
|
package/dist/index.js
CHANGED
|
@@ -87,7 +87,9 @@ function ensureCaptureInterceptor() {
|
|
|
87
87
|
calls
|
|
88
88
|
);
|
|
89
89
|
}
|
|
90
|
+
const startTime = Date.now();
|
|
90
91
|
const response = await _realOriginalFetch(input, init);
|
|
92
|
+
const endTime = Date.now();
|
|
91
93
|
const responseBody = await response.clone().text();
|
|
92
94
|
const responseHeaders = {};
|
|
93
95
|
response.headers.forEach((v, k) => {
|
|
@@ -101,7 +103,9 @@ function ensureCaptureInterceptor() {
|
|
|
101
103
|
responseStatus: response.status,
|
|
102
104
|
responseHeaders,
|
|
103
105
|
responseBody,
|
|
104
|
-
timestamp:
|
|
106
|
+
timestamp: endTime,
|
|
107
|
+
startTime,
|
|
108
|
+
endTime
|
|
105
109
|
});
|
|
106
110
|
return response;
|
|
107
111
|
};
|
|
@@ -154,7 +158,9 @@ function installNetworkInterceptor(mode, calls) {
|
|
|
154
158
|
calls
|
|
155
159
|
);
|
|
156
160
|
}
|
|
161
|
+
const startTime = Date.now();
|
|
157
162
|
const response = await originalFetch2(input, init);
|
|
163
|
+
const endTime = Date.now();
|
|
158
164
|
const responseBody = await response.clone().text();
|
|
159
165
|
const responseHeaders = {};
|
|
160
166
|
response.headers.forEach((v, k) => {
|
|
@@ -168,7 +174,9 @@ function installNetworkInterceptor(mode, calls) {
|
|
|
168
174
|
responseStatus: response.status,
|
|
169
175
|
responseHeaders,
|
|
170
176
|
responseBody,
|
|
171
|
-
timestamp:
|
|
177
|
+
timestamp: endTime,
|
|
178
|
+
startTime,
|
|
179
|
+
endTime
|
|
172
180
|
});
|
|
173
181
|
return response;
|
|
174
182
|
};
|
|
@@ -280,7 +288,9 @@ async function handleNeonSqlRequest(originalFetch, input, init, url, method, req
|
|
|
280
288
|
...init,
|
|
281
289
|
body: JSON.stringify({ queries: txBody })
|
|
282
290
|
};
|
|
291
|
+
const startTime = Date.now();
|
|
283
292
|
const response = await originalFetch(input, modifiedInit);
|
|
293
|
+
const endTime = Date.now();
|
|
284
294
|
const rawBody = await response.clone().text();
|
|
285
295
|
const responseHeaders = {};
|
|
286
296
|
response.headers.forEach((v, k) => {
|
|
@@ -306,7 +316,9 @@ async function handleNeonSqlRequest(originalFetch, input, init, url, method, req
|
|
|
306
316
|
responseStatus: response.status,
|
|
307
317
|
responseHeaders,
|
|
308
318
|
responseBody: recordedBody,
|
|
309
|
-
timestamp:
|
|
319
|
+
timestamp: endTime,
|
|
320
|
+
startTime,
|
|
321
|
+
endTime
|
|
310
322
|
});
|
|
311
323
|
return new Response(recordedBody, {
|
|
312
324
|
status: response.status,
|
|
@@ -718,7 +730,8 @@ async function finishRequest(requestContext, callbacks, response, options) {
|
|
|
718
730
|
handlerResponse: {
|
|
719
731
|
statusCode: response.statusCode ?? response.status ?? 0,
|
|
720
732
|
body: typeof response.body === "string" ? response.body : void 0
|
|
721
|
-
}
|
|
733
|
+
},
|
|
734
|
+
originalRequestId: options?.originalRequestId
|
|
722
735
|
};
|
|
723
736
|
const blobData = redactBlobData(rawBlobData);
|
|
724
737
|
const blobContent = JSON.stringify(blobData);
|
|
@@ -749,9 +762,13 @@ async function finishRequest(requestContext, callbacks, response, options) {
|
|
|
749
762
|
|
|
750
763
|
// src/createRecordingRequestHandler.ts
|
|
751
764
|
import crypto2 from "crypto";
|
|
765
|
+
var _originalRequestId = null;
|
|
752
766
|
function createRecordingRequestHandler(handler, options) {
|
|
753
767
|
return async (event, context) => {
|
|
754
768
|
const requestId = crypto2.randomUUID();
|
|
769
|
+
if (_originalRequestId === null) {
|
|
770
|
+
_originalRequestId = requestId;
|
|
771
|
+
}
|
|
755
772
|
return runInRequestContext(requestId, async () => {
|
|
756
773
|
const reqContext = startRequest(event);
|
|
757
774
|
let response;
|
|
@@ -774,7 +791,7 @@ function createRecordingRequestHandler(handler, options) {
|
|
|
774
791
|
statusCode: 500,
|
|
775
792
|
body: JSON.stringify({ error: errorMessage })
|
|
776
793
|
};
|
|
777
|
-
const finishOpts2 = { ...options, requestId };
|
|
794
|
+
const finishOpts2 = { ...options, requestId, originalRequestId: _originalRequestId };
|
|
778
795
|
const ctx2 = context;
|
|
779
796
|
if (ctx2 && typeof ctx2.waitUntil === "function") {
|
|
780
797
|
ctx2.waitUntil(
|
|
@@ -813,7 +830,7 @@ function createRecordingRequestHandler(handler, options) {
|
|
|
813
830
|
"X-Replay-Request-Id": requestId
|
|
814
831
|
}
|
|
815
832
|
};
|
|
816
|
-
const finishOpts = { ...options, requestId };
|
|
833
|
+
const finishOpts = { ...options, requestId, originalRequestId: _originalRequestId };
|
|
817
834
|
const ctx = context;
|
|
818
835
|
if (ctx && typeof ctx.waitUntil === "function") {
|
|
819
836
|
ctx.waitUntil(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replayio-app-building/netlify-recorder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "Capture and replay Netlify function executions as Replay recordings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@replayio/app-building": "^1.
|
|
32
|
+
"@replayio/app-building": "^1.29.0",
|
|
33
33
|
"@types/node": "^25.6.0",
|
|
34
34
|
"tsup": "^8.5.1",
|
|
35
35
|
"typescript": "^5.7.3"
|