@replayio-app-building/netlify-recorder 0.50.0 → 0.51.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 CHANGED
@@ -74,8 +74,10 @@ interface NetworkCall {
74
74
  timestamp: number;
75
75
  /** Epoch ms when the fetch call started. */
76
76
  startTime: number;
77
- /** Epoch ms when the response was received. */
77
+ /** Epoch ms when the response was received. 0 if response was never awaited (fire-and-forget). */
78
78
  endTime: number;
79
+ /** True when the call was initiated but the response was not awaited by the handler. */
80
+ pending?: boolean;
79
81
  }
80
82
  interface EnvRead {
81
83
  key: string;
package/dist/index.js CHANGED
@@ -102,37 +102,46 @@ function patchHttpModules(mode, calls, consumed, silent) {
102
102
  return origEnd(chunk, ...rest);
103
103
  };
104
104
  const startTime = Date.now();
105
+ const requestHeaders = {};
106
+ if (options.headers) {
107
+ for (const [k, v] of Object.entries(options.headers)) {
108
+ if (v !== void 0) requestHeaders[k] = Array.isArray(v) ? v.join(", ") : String(v);
109
+ }
110
+ }
111
+ const store = getRequestStore();
112
+ const targetCalls = store?.networkCalls ?? calls;
113
+ const entry = {
114
+ url: urlStr,
115
+ method,
116
+ requestHeaders,
117
+ requestBody: bodyChunks.length > 0 ? Buffer.concat(bodyChunks).toString("utf-8") : void 0,
118
+ responseStatus: 0,
119
+ responseHeaders: {},
120
+ responseBody: void 0,
121
+ timestamp: startTime,
122
+ startTime,
123
+ endTime: 0,
124
+ pending: true
125
+ };
126
+ targetCalls.push(entry);
105
127
  req.on("response", (res) => {
106
128
  const resChunks = [];
107
129
  res.on("data", (chunk) => resChunks.push(chunk));
108
130
  res.on("end", () => {
109
131
  const endTime = Date.now();
110
- const requestHeaders = {};
111
- if (options.headers) {
112
- for (const [k, v] of Object.entries(options.headers)) {
113
- if (v !== void 0) requestHeaders[k] = Array.isArray(v) ? v.join(", ") : String(v);
114
- }
115
- }
116
132
  const responseHeaders = {};
117
133
  if (res.headers) {
118
134
  for (const [k, v] of Object.entries(res.headers)) {
119
135
  if (v !== void 0) responseHeaders[k] = Array.isArray(v) ? v.join(", ") : String(v);
120
136
  }
121
137
  }
122
- const store = getRequestStore();
123
- const targetCalls = store?.networkCalls ?? calls;
124
- targetCalls.push({
125
- url: urlStr,
126
- method,
127
- requestHeaders,
128
- requestBody: bodyChunks.length > 0 ? Buffer.concat(bodyChunks).toString("utf-8") : void 0,
129
- responseStatus: res.statusCode ?? 0,
130
- responseHeaders,
131
- responseBody: Buffer.concat(resChunks).toString("utf-8"),
132
- timestamp: endTime,
133
- startTime,
134
- endTime
135
- });
138
+ entry.requestBody = bodyChunks.length > 0 ? Buffer.concat(bodyChunks).toString("utf-8") : void 0;
139
+ entry.responseStatus = res.statusCode ?? 0;
140
+ entry.responseHeaders = responseHeaders;
141
+ entry.responseBody = Buffer.concat(resChunks).toString("utf-8");
142
+ entry.timestamp = endTime;
143
+ entry.endTime = endTime;
144
+ entry.pending = false;
136
145
  });
137
146
  });
138
147
  return req;
@@ -173,11 +182,18 @@ function replayHttpRequest(url, _method, calls, consumed, callback, silent) {
173
182
  );
174
183
  }
175
184
  consumed.add(matchIdx);
185
+ const isPending = call.pending || call.endTime === 0 && call.responseStatus === 0;
176
186
  if (!silent) {
177
- const duration = call.endTime - call.startTime;
178
- console.log(
179
- ` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => ${call.responseStatus} (original: ${duration}ms)`
180
- );
187
+ if (isPending) {
188
+ console.log(
189
+ ` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => (fire-and-forget, no response captured)`
190
+ );
191
+ } else {
192
+ const duration = call.endTime - call.startTime;
193
+ console.log(
194
+ ` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => ${call.responseStatus} (original: ${duration}ms)`
195
+ );
196
+ }
181
197
  }
182
198
  const body = call.responseBody ?? "";
183
199
  const fakeRes = new Readable({
@@ -186,7 +202,7 @@ function replayHttpRequest(url, _method, calls, consumed, callback, silent) {
186
202
  this.push(null);
187
203
  }
188
204
  });
189
- fakeRes.statusCode = call.responseStatus;
205
+ fakeRes.statusCode = isPending ? 200 : call.responseStatus;
190
206
  fakeRes.statusMessage = "";
191
207
  fakeRes.headers = {};
192
208
  if (call.responseHeaders) {
@@ -246,6 +262,20 @@ function ensureCaptureInterceptor() {
246
262
  );
247
263
  }
248
264
  const startTime = Date.now();
265
+ const entry = {
266
+ url,
267
+ method,
268
+ requestHeaders,
269
+ requestBody,
270
+ responseStatus: 0,
271
+ responseHeaders: {},
272
+ responseBody: void 0,
273
+ timestamp: startTime,
274
+ startTime,
275
+ endTime: 0,
276
+ pending: true
277
+ };
278
+ calls.push(entry);
249
279
  const response = await _realOriginalFetch(input, init);
250
280
  const endTime = Date.now();
251
281
  const responseBody = await response.clone().text();
@@ -253,18 +283,12 @@ function ensureCaptureInterceptor() {
253
283
  response.headers.forEach((v, k) => {
254
284
  responseHeaders[k] = v;
255
285
  });
256
- calls.push({
257
- url,
258
- method,
259
- requestHeaders,
260
- requestBody,
261
- responseStatus: response.status,
262
- responseHeaders,
263
- responseBody,
264
- timestamp: endTime,
265
- startTime,
266
- endTime
267
- });
286
+ entry.responseStatus = response.status;
287
+ entry.responseHeaders = responseHeaders;
288
+ entry.responseBody = responseBody;
289
+ entry.timestamp = endTime;
290
+ entry.endTime = endTime;
291
+ entry.pending = false;
268
292
  return response;
269
293
  };
270
294
  globalThis.fetch = captureFetch;
@@ -320,6 +344,20 @@ function installNetworkInterceptor(mode, calls, options) {
320
344
  );
321
345
  }
322
346
  const startTime = Date.now();
347
+ const entry = {
348
+ url,
349
+ method,
350
+ requestHeaders,
351
+ requestBody,
352
+ responseStatus: 0,
353
+ responseHeaders: {},
354
+ responseBody: void 0,
355
+ timestamp: startTime,
356
+ startTime,
357
+ endTime: 0,
358
+ pending: true
359
+ };
360
+ calls.push(entry);
323
361
  const response = await originalFetch2(input, init);
324
362
  const endTime = Date.now();
325
363
  const responseBody = await response.clone().text();
@@ -327,18 +365,12 @@ function installNetworkInterceptor(mode, calls, options) {
327
365
  response.headers.forEach((v, k) => {
328
366
  responseHeaders[k] = v;
329
367
  });
330
- calls.push({
331
- url,
332
- method,
333
- requestHeaders,
334
- requestBody,
335
- responseStatus: response.status,
336
- responseHeaders,
337
- responseBody,
338
- timestamp: endTime,
339
- startTime,
340
- endTime
341
- });
368
+ entry.responseStatus = response.status;
369
+ entry.responseHeaders = responseHeaders;
370
+ entry.responseBody = responseBody;
371
+ entry.timestamp = endTime;
372
+ entry.endTime = endTime;
373
+ entry.pending = false;
342
374
  return response;
343
375
  };
344
376
  globalThis.fetch = captureFetch;
@@ -388,14 +420,21 @@ function installNetworkInterceptor(mode, calls, options) {
388
420
  );
389
421
  }
390
422
  consumed.add(matchIdx);
423
+ const isPending = call.pending || call.endTime === 0 && call.responseStatus === 0;
391
424
  if (!silent) {
392
- const duration = call.endTime - call.startTime;
393
- console.log(
394
- ` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => ${call.responseStatus} (original: ${duration}ms)`
395
- );
425
+ if (isPending) {
426
+ console.log(
427
+ ` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => (fire-and-forget, no response captured)`
428
+ );
429
+ } else {
430
+ const duration = call.endTime - call.startTime;
431
+ console.log(
432
+ ` [network-replay] Consumed call ${consumed.size}/${calls.length}: ${call.method} ${call.url} => ${call.responseStatus} (original: ${duration}ms)`
433
+ );
434
+ }
396
435
  }
397
436
  const body = call.responseBody ?? "";
398
- const status = call.responseStatus;
437
+ const status = isPending ? 200 : call.responseStatus;
399
438
  return {
400
439
  ok: status >= 200 && status < 300,
401
440
  status,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayio-app-building/netlify-recorder",
3
- "version": "0.50.0",
3
+ "version": "0.51.0",
4
4
  "description": "Capture and replay Netlify function executions as Replay recordings",
5
5
  "type": "module",
6
6
  "exports": {