rezo 1.0.19 → 1.0.20

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.
Files changed (38) hide show
  1. package/dist/adapters/curl.cjs +39 -34
  2. package/dist/adapters/curl.js +39 -34
  3. package/dist/adapters/entries/curl.d.ts +19 -17
  4. package/dist/adapters/entries/fetch.d.ts +19 -17
  5. package/dist/adapters/entries/http.d.ts +19 -17
  6. package/dist/adapters/entries/http2.d.ts +19 -17
  7. package/dist/adapters/entries/react-native.d.ts +19 -17
  8. package/dist/adapters/entries/xhr.d.ts +19 -17
  9. package/dist/adapters/fetch.cjs +42 -41
  10. package/dist/adapters/fetch.js +42 -41
  11. package/dist/adapters/http.cjs +65 -46
  12. package/dist/adapters/http.js +65 -46
  13. package/dist/adapters/http2.cjs +41 -36
  14. package/dist/adapters/http2.js +41 -36
  15. package/dist/adapters/index.cjs +6 -6
  16. package/dist/adapters/react-native.cjs +41 -27
  17. package/dist/adapters/react-native.js +41 -27
  18. package/dist/adapters/xhr.cjs +43 -38
  19. package/dist/adapters/xhr.js +43 -38
  20. package/dist/cache/index.cjs +13 -13
  21. package/dist/crawler.d.ts +19 -17
  22. package/dist/entries/crawler.cjs +5 -5
  23. package/dist/index.cjs +24 -24
  24. package/dist/index.d.ts +19 -17
  25. package/dist/platform/browser.d.ts +19 -17
  26. package/dist/platform/bun.d.ts +19 -17
  27. package/dist/platform/deno.d.ts +19 -17
  28. package/dist/platform/node.d.ts +19 -17
  29. package/dist/platform/react-native.d.ts +19 -17
  30. package/dist/platform/worker.d.ts +19 -17
  31. package/dist/plugin/index.cjs +36 -36
  32. package/dist/proxy/index.cjs +2 -2
  33. package/dist/queue/index.cjs +8 -8
  34. package/dist/utils/http-config.cjs +5 -3
  35. package/dist/utils/http-config.js +5 -3
  36. package/dist/utils/timing.cjs +90 -0
  37. package/dist/utils/timing.js +78 -0
  38. package/package.json +1 -1
@@ -200,6 +200,30 @@ class Http2SessionPool {
200
200
  this.closeAllSessions();
201
201
  }
202
202
  }
203
+ function updateTiming(config, timing, contentLengthCounter) {
204
+ const now = performance.now();
205
+ config.timing.domainLookupStart = timing.dnsStart || config.timing.startTime;
206
+ config.timing.domainLookupEnd = timing.dnsEnd || timing.dnsStart || config.timing.startTime;
207
+ config.timing.connectStart = timing.tcpStart || timing.dnsEnd || config.timing.startTime;
208
+ config.timing.secureConnectionStart = timing.tlsStart || 0;
209
+ config.timing.connectEnd = timing.tcpEnd || timing.tlsEnd || timing.tcpStart || config.timing.startTime;
210
+ config.timing.requestStart = timing.tcpEnd || config.timing.startTime;
211
+ config.timing.responseStart = timing.firstByteTime || config.timing.requestStart;
212
+ config.timing.responseEnd = now;
213
+ config.transfer.bodySize = contentLengthCounter;
214
+ config.transfer.responseSize = contentLengthCounter;
215
+ }
216
+ function getTimingDurations(config) {
217
+ const t = config.timing;
218
+ return {
219
+ total: t.responseEnd - t.startTime,
220
+ dns: t.domainLookupEnd - t.domainLookupStart,
221
+ tcp: t.secureConnectionStart > 0 ? t.secureConnectionStart - t.connectStart : t.connectEnd - t.connectStart,
222
+ tls: t.secureConnectionStart > 0 ? t.connectEnd - t.secureConnectionStart : undefined,
223
+ firstByte: t.responseStart - t.startTime,
224
+ download: t.responseEnd - t.responseStart
225
+ };
226
+ }
203
227
  const responseCacheInstances = new Map;
204
228
  function getCacheConfigKey(option) {
205
229
  if (option === true)
@@ -489,10 +513,11 @@ async function executeHttp2Request(fetchOptions, config, options, perform, fs, s
489
513
  const maxRetries = config?.retry?.maxRetries || 0;
490
514
  const incrementDelay = config?.retry?.incrementDelay || false;
491
515
  const statusCodes = config?.retry?.statusCodes;
516
+ const startTime = performance.now();
492
517
  const timing = {
493
- startTime: performance.now(),
494
- startTimestamp: Date.now()
518
+ startTime
495
519
  };
520
+ config.timing.startTime = startTime;
496
521
  const ABSOLUTE_MAX_ATTEMPTS = 50;
497
522
  const visitedUrls = new Set;
498
523
  let totalAttempts = 0;
@@ -662,7 +687,6 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
662
687
  config.isSecure = isSecure;
663
688
  config.finalUrl = url.href;
664
689
  config.network.protocol = "h2";
665
- config.timing.startTimestamp = timing.startTimestamp;
666
690
  }
667
691
  const headers = {
668
692
  [http2.constants.HTTP2_HEADER_METHOD]: fetchOptions.method.toUpperCase(),
@@ -739,9 +763,9 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
739
763
  responseHeaders = headers;
740
764
  status = Number(headers[http2.constants.HTTP2_HEADER_STATUS]) || 200;
741
765
  statusText = getStatusText(status);
742
- if (!config.timing.ttfbMs) {
766
+ if (!timing.firstByteTime) {
743
767
  timing.firstByteTime = performance.now();
744
- config.timing.ttfbMs = timing.firstByteTime - timing.startTime;
768
+ config.timing.responseStart = timing.firstByteTime;
745
769
  }
746
770
  const location = headers["location"];
747
771
  const isRedirect = status >= 300 && status < 400 && location;
@@ -760,8 +784,8 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
760
784
  contentLength: headers["content-length"] ? parseInt(headers["content-length"], 10) : undefined,
761
785
  cookies: config.responseCookies?.array || [],
762
786
  timing: {
763
- firstByte: config.timing.ttfbMs,
764
- total: performance.now() - timing.startTime
787
+ firstByte: config.timing.responseStart - config.timing.startTime,
788
+ total: performance.now() - config.timing.startTime
765
789
  }
766
790
  };
767
791
  eventEmitter.emit("headers", headersEvent);
@@ -798,9 +822,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
798
822
  }
799
823
  });
800
824
  req.on("end", async () => {
801
- config.timing.endTimestamp = Date.now();
802
- config.timing.durationMs = performance.now() - timing.startTime;
803
- config.timing.transferMs = timing.firstByteTime ? performance.now() - timing.firstByteTime : config.timing.durationMs;
825
+ updateTiming(config, timing, contentLengthCounter);
804
826
  if (!config.transfer) {
805
827
  config.transfer = { requestSize: 0, responseSize: 0, headerSize: 0, bodySize: 0 };
806
828
  }
@@ -820,8 +842,6 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
820
842
  config.transfer.requestSize = Buffer.byteLength(JSON.stringify(body), "utf8");
821
843
  }
822
844
  }
823
- config.transfer.bodySize = contentLengthCounter;
824
- config.transfer.responseSize = contentLengthCounter;
825
845
  (sessionPool || Http2SessionPool.getInstance()).releaseSession(url);
826
846
  if (_stats.statusOnNext === "redirect") {
827
847
  const partialResponse = {
@@ -920,14 +940,10 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
920
940
  fileName: config.fileName,
921
941
  fileSize: responseBody.length,
922
942
  timing: {
923
- total: config.timing.durationMs || 0,
924
- dns: config.timing.dnsMs,
925
- tcp: config.timing.tcpMs,
926
- tls: config.timing.tlsMs,
927
- firstByte: config.timing.ttfbMs,
928
- download: config.timing.transferMs || 0
943
+ ...getTimingDurations(config),
944
+ download: getTimingDurations(config).download || 0
929
945
  },
930
- averageSpeed: config.timing.transferMs ? responseBody.length / config.timing.transferMs * 1000 : 0,
946
+ averageSpeed: getTimingDurations(config).download ? responseBody.length / getTimingDurations(config).download * 1000 : 0,
931
947
  config: sanitizeConfig(config)
932
948
  };
933
949
  downloadResult.emit("finish", downloadFinishEvent);
@@ -962,14 +978,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
962
978
  finalUrl: url.href,
963
979
  cookies: config.responseCookies || { array: [], serialized: [], netscape: "", string: "", setCookiesString: [] },
964
980
  urls: buildUrlTree(config, url.href),
965
- timing: {
966
- total: config.timing.durationMs || 0,
967
- dns: config.timing.dnsMs,
968
- tcp: config.timing.tcpMs,
969
- tls: config.timing.tlsMs,
970
- firstByte: config.timing.ttfbMs,
971
- download: config.timing.transferMs
972
- },
981
+ timing: getTimingDurations(config),
973
982
  config: sanitizeConfig(config)
974
983
  };
975
984
  streamResult.emit("finish", streamFinishEvent);
@@ -992,16 +1001,12 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
992
1001
  urls: buildUrlTree(config, url.href),
993
1002
  uploadSize: config.transfer.requestSize || 0,
994
1003
  timing: {
995
- total: config.timing.durationMs || 0,
996
- dns: config.timing.dnsMs,
997
- tcp: config.timing.tcpMs,
998
- tls: config.timing.tlsMs,
999
- upload: config.timing.transferMs || 0,
1000
- waiting: config.timing.ttfbMs || 0,
1001
- download: config.timing.transferMs
1004
+ ...getTimingDurations(config),
1005
+ upload: getTimingDurations(config).firstByte || 0,
1006
+ waiting: getTimingDurations(config).download > 0 && getTimingDurations(config).firstByte > 0 ? getTimingDurations(config).download - getTimingDurations(config).firstByte : 0
1002
1007
  },
1003
- averageUploadSpeed: config.timing.transferMs ? (config.transfer.requestSize || 0) / config.timing.transferMs * 1000 : 0,
1004
- averageDownloadSpeed: config.timing.transferMs ? contentLengthCounter / config.timing.transferMs * 1000 : 0,
1008
+ averageUploadSpeed: getTimingDurations(config).firstByte && config.transfer.requestSize ? config.transfer.requestSize / getTimingDurations(config).firstByte * 1000 : 0,
1009
+ averageDownloadSpeed: getTimingDurations(config).download ? contentLengthCounter / getTimingDurations(config).download * 1000 : 0,
1005
1010
  config: sanitizeConfig(config)
1006
1011
  };
1007
1012
  uploadResult.emit("finish", uploadFinishEvent);
@@ -200,6 +200,30 @@ class Http2SessionPool {
200
200
  this.closeAllSessions();
201
201
  }
202
202
  }
203
+ function updateTiming(config, timing, contentLengthCounter) {
204
+ const now = performance.now();
205
+ config.timing.domainLookupStart = timing.dnsStart || config.timing.startTime;
206
+ config.timing.domainLookupEnd = timing.dnsEnd || timing.dnsStart || config.timing.startTime;
207
+ config.timing.connectStart = timing.tcpStart || timing.dnsEnd || config.timing.startTime;
208
+ config.timing.secureConnectionStart = timing.tlsStart || 0;
209
+ config.timing.connectEnd = timing.tcpEnd || timing.tlsEnd || timing.tcpStart || config.timing.startTime;
210
+ config.timing.requestStart = timing.tcpEnd || config.timing.startTime;
211
+ config.timing.responseStart = timing.firstByteTime || config.timing.requestStart;
212
+ config.timing.responseEnd = now;
213
+ config.transfer.bodySize = contentLengthCounter;
214
+ config.transfer.responseSize = contentLengthCounter;
215
+ }
216
+ function getTimingDurations(config) {
217
+ const t = config.timing;
218
+ return {
219
+ total: t.responseEnd - t.startTime,
220
+ dns: t.domainLookupEnd - t.domainLookupStart,
221
+ tcp: t.secureConnectionStart > 0 ? t.secureConnectionStart - t.connectStart : t.connectEnd - t.connectStart,
222
+ tls: t.secureConnectionStart > 0 ? t.connectEnd - t.secureConnectionStart : undefined,
223
+ firstByte: t.responseStart - t.startTime,
224
+ download: t.responseEnd - t.responseStart
225
+ };
226
+ }
203
227
  const responseCacheInstances = new Map;
204
228
  function getCacheConfigKey(option) {
205
229
  if (option === true)
@@ -489,10 +513,11 @@ async function executeHttp2Request(fetchOptions, config, options, perform, fs, s
489
513
  const maxRetries = config?.retry?.maxRetries || 0;
490
514
  const incrementDelay = config?.retry?.incrementDelay || false;
491
515
  const statusCodes = config?.retry?.statusCodes;
516
+ const startTime = performance.now();
492
517
  const timing = {
493
- startTime: performance.now(),
494
- startTimestamp: Date.now()
518
+ startTime
495
519
  };
520
+ config.timing.startTime = startTime;
496
521
  const ABSOLUTE_MAX_ATTEMPTS = 50;
497
522
  const visitedUrls = new Set;
498
523
  let totalAttempts = 0;
@@ -662,7 +687,6 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
662
687
  config.isSecure = isSecure;
663
688
  config.finalUrl = url.href;
664
689
  config.network.protocol = "h2";
665
- config.timing.startTimestamp = timing.startTimestamp;
666
690
  }
667
691
  const headers = {
668
692
  [http2.constants.HTTP2_HEADER_METHOD]: fetchOptions.method.toUpperCase(),
@@ -739,9 +763,9 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
739
763
  responseHeaders = headers;
740
764
  status = Number(headers[http2.constants.HTTP2_HEADER_STATUS]) || 200;
741
765
  statusText = getStatusText(status);
742
- if (!config.timing.ttfbMs) {
766
+ if (!timing.firstByteTime) {
743
767
  timing.firstByteTime = performance.now();
744
- config.timing.ttfbMs = timing.firstByteTime - timing.startTime;
768
+ config.timing.responseStart = timing.firstByteTime;
745
769
  }
746
770
  const location = headers["location"];
747
771
  const isRedirect = status >= 300 && status < 400 && location;
@@ -760,8 +784,8 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
760
784
  contentLength: headers["content-length"] ? parseInt(headers["content-length"], 10) : undefined,
761
785
  cookies: config.responseCookies?.array || [],
762
786
  timing: {
763
- firstByte: config.timing.ttfbMs,
764
- total: performance.now() - timing.startTime
787
+ firstByte: config.timing.responseStart - config.timing.startTime,
788
+ total: performance.now() - config.timing.startTime
765
789
  }
766
790
  };
767
791
  eventEmitter.emit("headers", headersEvent);
@@ -798,9 +822,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
798
822
  }
799
823
  });
800
824
  req.on("end", async () => {
801
- config.timing.endTimestamp = Date.now();
802
- config.timing.durationMs = performance.now() - timing.startTime;
803
- config.timing.transferMs = timing.firstByteTime ? performance.now() - timing.firstByteTime : config.timing.durationMs;
825
+ updateTiming(config, timing, contentLengthCounter);
804
826
  if (!config.transfer) {
805
827
  config.transfer = { requestSize: 0, responseSize: 0, headerSize: 0, bodySize: 0 };
806
828
  }
@@ -820,8 +842,6 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
820
842
  config.transfer.requestSize = Buffer.byteLength(JSON.stringify(body), "utf8");
821
843
  }
822
844
  }
823
- config.transfer.bodySize = contentLengthCounter;
824
- config.transfer.responseSize = contentLengthCounter;
825
845
  (sessionPool || Http2SessionPool.getInstance()).releaseSession(url);
826
846
  if (_stats.statusOnNext === "redirect") {
827
847
  const partialResponse = {
@@ -920,14 +940,10 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
920
940
  fileName: config.fileName,
921
941
  fileSize: responseBody.length,
922
942
  timing: {
923
- total: config.timing.durationMs || 0,
924
- dns: config.timing.dnsMs,
925
- tcp: config.timing.tcpMs,
926
- tls: config.timing.tlsMs,
927
- firstByte: config.timing.ttfbMs,
928
- download: config.timing.transferMs || 0
943
+ ...getTimingDurations(config),
944
+ download: getTimingDurations(config).download || 0
929
945
  },
930
- averageSpeed: config.timing.transferMs ? responseBody.length / config.timing.transferMs * 1000 : 0,
946
+ averageSpeed: getTimingDurations(config).download ? responseBody.length / getTimingDurations(config).download * 1000 : 0,
931
947
  config: sanitizeConfig(config)
932
948
  };
933
949
  downloadResult.emit("finish", downloadFinishEvent);
@@ -962,14 +978,7 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
962
978
  finalUrl: url.href,
963
979
  cookies: config.responseCookies || { array: [], serialized: [], netscape: "", string: "", setCookiesString: [] },
964
980
  urls: buildUrlTree(config, url.href),
965
- timing: {
966
- total: config.timing.durationMs || 0,
967
- dns: config.timing.dnsMs,
968
- tcp: config.timing.tcpMs,
969
- tls: config.timing.tlsMs,
970
- firstByte: config.timing.ttfbMs,
971
- download: config.timing.transferMs
972
- },
981
+ timing: getTimingDurations(config),
973
982
  config: sanitizeConfig(config)
974
983
  };
975
984
  streamResult.emit("finish", streamFinishEvent);
@@ -992,16 +1001,12 @@ async function executeHttp2Stream(config, fetchOptions, requestCount, timing, _s
992
1001
  urls: buildUrlTree(config, url.href),
993
1002
  uploadSize: config.transfer.requestSize || 0,
994
1003
  timing: {
995
- total: config.timing.durationMs || 0,
996
- dns: config.timing.dnsMs,
997
- tcp: config.timing.tcpMs,
998
- tls: config.timing.tlsMs,
999
- upload: config.timing.transferMs || 0,
1000
- waiting: config.timing.ttfbMs || 0,
1001
- download: config.timing.transferMs
1004
+ ...getTimingDurations(config),
1005
+ upload: getTimingDurations(config).firstByte || 0,
1006
+ waiting: getTimingDurations(config).download > 0 && getTimingDurations(config).firstByte > 0 ? getTimingDurations(config).download - getTimingDurations(config).firstByte : 0
1002
1007
  },
1003
- averageUploadSpeed: config.timing.transferMs ? (config.transfer.requestSize || 0) / config.timing.transferMs * 1000 : 0,
1004
- averageDownloadSpeed: config.timing.transferMs ? contentLengthCounter / config.timing.transferMs * 1000 : 0,
1008
+ averageUploadSpeed: getTimingDurations(config).firstByte && config.transfer.requestSize ? config.transfer.requestSize / getTimingDurations(config).firstByte * 1000 : 0,
1009
+ averageDownloadSpeed: getTimingDurations(config).download ? contentLengthCounter / getTimingDurations(config).download * 1000 : 0,
1005
1010
  config: sanitizeConfig(config)
1006
1011
  };
1007
1012
  uploadResult.emit("finish", uploadFinishEvent);
@@ -1,6 +1,6 @@
1
- const _mod_i8j93l = require('./picker.cjs');
2
- exports.detectRuntime = _mod_i8j93l.detectRuntime;
3
- exports.getAdapterCapabilities = _mod_i8j93l.getAdapterCapabilities;
4
- exports.buildAdapterContext = _mod_i8j93l.buildAdapterContext;
5
- exports.getAvailableAdapters = _mod_i8j93l.getAvailableAdapters;
6
- exports.selectAdapter = _mod_i8j93l.selectAdapter;;
1
+ const _mod_dy07ge = require('./picker.cjs');
2
+ exports.detectRuntime = _mod_dy07ge.detectRuntime;
3
+ exports.getAdapterCapabilities = _mod_dy07ge.getAdapterCapabilities;
4
+ exports.buildAdapterContext = _mod_dy07ge.buildAdapterContext;
5
+ exports.getAvailableAdapters = _mod_dy07ge.getAvailableAdapters;
6
+ exports.selectAdapter = _mod_dy07ge.selectAdapter;;
@@ -17,6 +17,30 @@ const Environment = {
17
17
  hasFormData: typeof FormData !== "undefined",
18
18
  hasAbortController: typeof AbortController !== "undefined"
19
19
  };
20
+ function updateTiming(config, timing, bodySize) {
21
+ const now = performance.now();
22
+ config.timing.domainLookupStart = config.timing.startTime;
23
+ config.timing.domainLookupEnd = config.timing.startTime;
24
+ config.timing.connectStart = config.timing.startTime;
25
+ config.timing.secureConnectionStart = 0;
26
+ config.timing.connectEnd = config.timing.startTime;
27
+ config.timing.requestStart = config.timing.startTime;
28
+ config.timing.responseStart = timing.firstByteTime || config.timing.startTime;
29
+ config.timing.responseEnd = now;
30
+ config.transfer.bodySize = bodySize;
31
+ config.transfer.responseSize = bodySize;
32
+ }
33
+ function getTimingDurations(config) {
34
+ const t = config.timing;
35
+ return {
36
+ total: t.responseEnd - t.startTime,
37
+ dns: t.domainLookupEnd - t.domainLookupStart,
38
+ tcp: t.secureConnectionStart > 0 ? t.secureConnectionStart - t.connectStart : t.connectEnd - t.connectStart,
39
+ tls: t.secureConnectionStart > 0 ? t.connectEnd - t.secureConnectionStart : undefined,
40
+ firstByte: t.responseStart - t.startTime,
41
+ download: t.responseEnd - t.responseStart
42
+ };
43
+ }
20
44
  const responseCacheInstances = new Map;
21
45
  function getCacheConfigKey(option) {
22
46
  if (option === true)
@@ -227,10 +251,11 @@ async function executeFetchRequest(fetchOptions, config, options, perform, strea
227
251
  const maxRetries = config?.retry?.maxRetries || 0;
228
252
  const incrementDelay = config?.retry?.incrementDelay || false;
229
253
  const statusCodes = config?.retry?.statusCodes;
254
+ const startTime = performance.now();
230
255
  const timing = {
231
- startTime: performance.now(),
232
- startTimestamp: Date.now()
256
+ startTime
233
257
  };
258
+ config.timing.startTime = startTime;
234
259
  const ABSOLUTE_MAX_ATTEMPTS = 50;
235
260
  let totalAttempts = 0;
236
261
  config.setSignal();
@@ -294,7 +319,6 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
294
319
  config.isSecure = isSecure;
295
320
  config.finalUrl = url;
296
321
  config.network.protocol = isSecure ? "https" : "http";
297
- config.timing.startTimestamp = timing.startTimestamp;
298
322
  const reqHeaders = fetchOptions.headers instanceof RezoHeaders ? fetchOptions.headers.toObject() : fetchOptions.headers || {};
299
323
  const headers = toFetchHeaders(reqHeaders);
300
324
  const eventEmitter = streamResult || downloadResult || uploadResult;
@@ -347,9 +371,9 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
347
371
  if (timeoutId)
348
372
  clearTimeout(timeoutId);
349
373
  }
350
- if (!config.timing.ttfbMs) {
374
+ if (!timing.firstByteTime) {
351
375
  timing.firstByteTime = performance.now();
352
- config.timing.ttfbMs = timing.firstByteTime - timing.startTime;
376
+ config.timing.responseStart = timing.firstByteTime;
353
377
  }
354
378
  const status = response.status;
355
379
  const statusText = response.statusText;
@@ -373,8 +397,8 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
373
397
  contentLength: contentLength ? parseInt(contentLength, 10) : undefined,
374
398
  cookies: cookies.array,
375
399
  timing: {
376
- firstByte: config.timing.ttfbMs,
377
- total: performance.now() - timing.startTime
400
+ firstByte: config.timing.responseStart - config.timing.startTime,
401
+ total: performance.now() - config.timing.startTime
378
402
  }
379
403
  };
380
404
  eventEmitter.emit("headers", headersEvent);
@@ -428,11 +452,7 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
428
452
  bodySize = text.length;
429
453
  }
430
454
  }
431
- config.timing.endTimestamp = Date.now();
432
- config.timing.durationMs = performance.now() - timing.startTime;
433
- config.timing.transferMs = timing.firstByteTime ? performance.now() - timing.firstByteTime : config.timing.durationMs;
434
- config.transfer.bodySize = bodySize;
435
- config.transfer.responseSize = bodySize;
455
+ updateTiming(config, timing, bodySize);
436
456
  if (status >= 400) {
437
457
  const error = builErrorFromResponse(`HTTP Error ${status}: ${statusText}`, {
438
458
  status,
@@ -466,11 +486,7 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
466
486
  finalUrl: url,
467
487
  cookies,
468
488
  urls: buildUrlTree(config, url),
469
- timing: {
470
- total: config.timing.durationMs || 0,
471
- firstByte: config.timing.ttfbMs,
472
- download: config.timing.transferMs
473
- },
489
+ timing: getTimingDurations(config),
474
490
  config: sanitizeConfig(config)
475
491
  };
476
492
  streamResult.emit("finish", streamFinishEvent);
@@ -491,11 +507,10 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
491
507
  fileName: config.fileName || "",
492
508
  fileSize: bodySize,
493
509
  timing: {
494
- total: config.timing.durationMs || 0,
495
- firstByte: config.timing.ttfbMs,
496
- download: config.timing.transferMs || 0
510
+ ...getTimingDurations(config),
511
+ download: getTimingDurations(config).download || 0
497
512
  },
498
- averageSpeed: config.timing.transferMs ? bodySize / config.timing.transferMs * 1000 : 0,
513
+ averageSpeed: getTimingDurations(config).download ? bodySize / getTimingDurations(config).download * 1000 : 0,
499
514
  config: sanitizeConfig(config)
500
515
  };
501
516
  downloadResult.emit("finish", downloadFinishEvent);
@@ -517,13 +532,12 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
517
532
  urls: buildUrlTree(config, url),
518
533
  uploadSize: config.transfer.requestSize || 0,
519
534
  timing: {
520
- total: config.timing.durationMs || 0,
521
- upload: config.timing.transferMs || 0,
522
- waiting: config.timing.ttfbMs || 0,
523
- download: config.timing.transferMs
535
+ ...getTimingDurations(config),
536
+ upload: getTimingDurations(config).firstByte || 0,
537
+ waiting: getTimingDurations(config).download > 0 && getTimingDurations(config).firstByte > 0 ? getTimingDurations(config).download - getTimingDurations(config).firstByte : 0
524
538
  },
525
- averageUploadSpeed: config.timing.transferMs ? (config.transfer.requestSize || 0) / config.timing.transferMs * 1000 : 0,
526
- averageDownloadSpeed: config.timing.transferMs ? bodySize / config.timing.transferMs * 1000 : 0,
539
+ averageUploadSpeed: getTimingDurations(config).firstByte && config.transfer.requestSize ? config.transfer.requestSize / getTimingDurations(config).firstByte * 1000 : 0,
540
+ averageDownloadSpeed: getTimingDurations(config).download ? bodySize / getTimingDurations(config).download * 1000 : 0,
527
541
  config: sanitizeConfig(config)
528
542
  };
529
543
  uploadResult.emit("finish", uploadFinishEvent);
@@ -17,6 +17,30 @@ const Environment = {
17
17
  hasFormData: typeof FormData !== "undefined",
18
18
  hasAbortController: typeof AbortController !== "undefined"
19
19
  };
20
+ function updateTiming(config, timing, bodySize) {
21
+ const now = performance.now();
22
+ config.timing.domainLookupStart = config.timing.startTime;
23
+ config.timing.domainLookupEnd = config.timing.startTime;
24
+ config.timing.connectStart = config.timing.startTime;
25
+ config.timing.secureConnectionStart = 0;
26
+ config.timing.connectEnd = config.timing.startTime;
27
+ config.timing.requestStart = config.timing.startTime;
28
+ config.timing.responseStart = timing.firstByteTime || config.timing.startTime;
29
+ config.timing.responseEnd = now;
30
+ config.transfer.bodySize = bodySize;
31
+ config.transfer.responseSize = bodySize;
32
+ }
33
+ function getTimingDurations(config) {
34
+ const t = config.timing;
35
+ return {
36
+ total: t.responseEnd - t.startTime,
37
+ dns: t.domainLookupEnd - t.domainLookupStart,
38
+ tcp: t.secureConnectionStart > 0 ? t.secureConnectionStart - t.connectStart : t.connectEnd - t.connectStart,
39
+ tls: t.secureConnectionStart > 0 ? t.connectEnd - t.secureConnectionStart : undefined,
40
+ firstByte: t.responseStart - t.startTime,
41
+ download: t.responseEnd - t.responseStart
42
+ };
43
+ }
20
44
  const responseCacheInstances = new Map;
21
45
  function getCacheConfigKey(option) {
22
46
  if (option === true)
@@ -227,10 +251,11 @@ async function executeFetchRequest(fetchOptions, config, options, perform, strea
227
251
  const maxRetries = config?.retry?.maxRetries || 0;
228
252
  const incrementDelay = config?.retry?.incrementDelay || false;
229
253
  const statusCodes = config?.retry?.statusCodes;
254
+ const startTime = performance.now();
230
255
  const timing = {
231
- startTime: performance.now(),
232
- startTimestamp: Date.now()
256
+ startTime
233
257
  };
258
+ config.timing.startTime = startTime;
234
259
  const ABSOLUTE_MAX_ATTEMPTS = 50;
235
260
  let totalAttempts = 0;
236
261
  config.setSignal();
@@ -294,7 +319,6 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
294
319
  config.isSecure = isSecure;
295
320
  config.finalUrl = url;
296
321
  config.network.protocol = isSecure ? "https" : "http";
297
- config.timing.startTimestamp = timing.startTimestamp;
298
322
  const reqHeaders = fetchOptions.headers instanceof RezoHeaders ? fetchOptions.headers.toObject() : fetchOptions.headers || {};
299
323
  const headers = toFetchHeaders(reqHeaders);
300
324
  const eventEmitter = streamResult || downloadResult || uploadResult;
@@ -347,9 +371,9 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
347
371
  if (timeoutId)
348
372
  clearTimeout(timeoutId);
349
373
  }
350
- if (!config.timing.ttfbMs) {
374
+ if (!timing.firstByteTime) {
351
375
  timing.firstByteTime = performance.now();
352
- config.timing.ttfbMs = timing.firstByteTime - timing.startTime;
376
+ config.timing.responseStart = timing.firstByteTime;
353
377
  }
354
378
  const status = response.status;
355
379
  const statusText = response.statusText;
@@ -373,8 +397,8 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
373
397
  contentLength: contentLength ? parseInt(contentLength, 10) : undefined,
374
398
  cookies: cookies.array,
375
399
  timing: {
376
- firstByte: config.timing.ttfbMs,
377
- total: performance.now() - timing.startTime
400
+ firstByte: config.timing.responseStart - config.timing.startTime,
401
+ total: performance.now() - config.timing.startTime
378
402
  }
379
403
  };
380
404
  eventEmitter.emit("headers", headersEvent);
@@ -428,11 +452,7 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
428
452
  bodySize = text.length;
429
453
  }
430
454
  }
431
- config.timing.endTimestamp = Date.now();
432
- config.timing.durationMs = performance.now() - timing.startTime;
433
- config.timing.transferMs = timing.firstByteTime ? performance.now() - timing.firstByteTime : config.timing.durationMs;
434
- config.transfer.bodySize = bodySize;
435
- config.transfer.responseSize = bodySize;
455
+ updateTiming(config, timing, bodySize);
436
456
  if (status >= 400) {
437
457
  const error = builErrorFromResponse(`HTTP Error ${status}: ${statusText}`, {
438
458
  status,
@@ -466,11 +486,7 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
466
486
  finalUrl: url,
467
487
  cookies,
468
488
  urls: buildUrlTree(config, url),
469
- timing: {
470
- total: config.timing.durationMs || 0,
471
- firstByte: config.timing.ttfbMs,
472
- download: config.timing.transferMs
473
- },
489
+ timing: getTimingDurations(config),
474
490
  config: sanitizeConfig(config)
475
491
  };
476
492
  streamResult.emit("finish", streamFinishEvent);
@@ -491,11 +507,10 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
491
507
  fileName: config.fileName || "",
492
508
  fileSize: bodySize,
493
509
  timing: {
494
- total: config.timing.durationMs || 0,
495
- firstByte: config.timing.ttfbMs,
496
- download: config.timing.transferMs || 0
510
+ ...getTimingDurations(config),
511
+ download: getTimingDurations(config).download || 0
497
512
  },
498
- averageSpeed: config.timing.transferMs ? bodySize / config.timing.transferMs * 1000 : 0,
513
+ averageSpeed: getTimingDurations(config).download ? bodySize / getTimingDurations(config).download * 1000 : 0,
499
514
  config: sanitizeConfig(config)
500
515
  };
501
516
  downloadResult.emit("finish", downloadFinishEvent);
@@ -517,13 +532,12 @@ async function executeSingleRequest(config, fetchOptions, timing, streamResult,
517
532
  urls: buildUrlTree(config, url),
518
533
  uploadSize: config.transfer.requestSize || 0,
519
534
  timing: {
520
- total: config.timing.durationMs || 0,
521
- upload: config.timing.transferMs || 0,
522
- waiting: config.timing.ttfbMs || 0,
523
- download: config.timing.transferMs
535
+ ...getTimingDurations(config),
536
+ upload: getTimingDurations(config).firstByte || 0,
537
+ waiting: getTimingDurations(config).download > 0 && getTimingDurations(config).firstByte > 0 ? getTimingDurations(config).download - getTimingDurations(config).firstByte : 0
524
538
  },
525
- averageUploadSpeed: config.timing.transferMs ? (config.transfer.requestSize || 0) / config.timing.transferMs * 1000 : 0,
526
- averageDownloadSpeed: config.timing.transferMs ? bodySize / config.timing.transferMs * 1000 : 0,
539
+ averageUploadSpeed: getTimingDurations(config).firstByte && config.transfer.requestSize ? config.transfer.requestSize / getTimingDurations(config).firstByte * 1000 : 0,
540
+ averageDownloadSpeed: getTimingDurations(config).download ? bodySize / getTimingDurations(config).download * 1000 : 0,
527
541
  config: sanitizeConfig(config)
528
542
  };
529
543
  uploadResult.emit("finish", uploadFinishEvent);