lighthouse 12.0.0-dev.20240610 → 12.0.0-dev.20240612

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 (118) hide show
  1. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
  2. package/core/audits/byte-efficiency/byte-efficiency-audit.js +2 -2
  3. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
  4. package/core/audits/byte-efficiency/render-blocking-resources.js +4 -4
  5. package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
  6. package/core/audits/dobetterweb/uses-http2.js +2 -2
  7. package/core/audits/long-tasks.d.ts +7 -6
  8. package/core/audits/long-tasks.js +5 -4
  9. package/core/audits/prioritize-lcp-image.d.ts +1 -1
  10. package/core/computed/document-urls.js +3 -2
  11. package/core/computed/load-simulator.d.ts +4 -4
  12. package/core/computed/load-simulator.js +3 -3
  13. package/core/computed/main-resource.js +3 -2
  14. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
  15. package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
  16. package/core/computed/metrics/lantern-interactive.d.ts +4 -4
  17. package/core/computed/metrics/lantern-interactive.js +3 -3
  18. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
  19. package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
  20. package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
  21. package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
  22. package/core/computed/metrics/lantern-metric.d.ts +4 -3
  23. package/core/computed/metrics/lantern-metric.js +4 -4
  24. package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
  25. package/core/computed/metrics/lantern-speed-index.js +3 -3
  26. package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
  27. package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
  28. package/core/computed/metrics/total-blocking-time.js +3 -1
  29. package/core/computed/network-analysis.js +2 -2
  30. package/core/computed/page-dependency-graph.d.ts +2 -2
  31. package/core/computed/page-dependency-graph.js +6 -6
  32. package/core/computed/processed-navigation.d.ts +1 -1
  33. package/core/computed/tbt-impact-tasks.js +4 -2
  34. package/core/config/constants.d.ts +28 -53
  35. package/core/config/constants.js +2 -43
  36. package/core/lib/asset-saver.js +2 -2
  37. package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
  38. package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
  39. package/core/lib/lantern/BaseNode.test.js +385 -0
  40. package/core/lib/lantern/CpuNode.d.ts +43 -0
  41. package/core/lib/lantern/{cpu-node.js → CpuNode.js} +8 -9
  42. package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
  43. package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +17 -17
  44. package/core/lib/lantern/{metric.js → Metric.js} +10 -12
  45. package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +4 -5
  46. package/core/lib/lantern/{network-node.js → NetworkNode.js} +4 -5
  47. package/core/lib/lantern/{page-dependency-graph.d.ts → PageDependencyGraph.d.ts} +22 -11
  48. package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +56 -22
  49. package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
  50. package/core/lib/lantern/{tbt-utils.d.ts → TBTUtils.d.ts} +1 -1
  51. package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
  52. package/core/lib/lantern/TBTUtils.test.js +130 -0
  53. package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts} +7 -7
  54. package/core/lib/lantern/{trace-engine-computation-data.js → TraceEngineComputationData.js} +18 -16
  55. package/core/lib/lantern/lantern.d.ts +19 -7
  56. package/core/lib/lantern/lantern.js +21 -1
  57. package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
  58. package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +8 -10
  59. package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
  60. package/core/lib/lantern/metrics/Interactive.d.ts +20 -0
  61. package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +14 -17
  62. package/core/lib/lantern/metrics/Interactive.test.js +56 -0
  63. package/core/lib/lantern/metrics/LargestContentfulPaint.d.ts +19 -0
  64. package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +12 -15
  65. package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
  66. package/core/lib/lantern/metrics/MaxPotentialFID.d.ts +24 -0
  67. package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +12 -13
  68. package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
  69. package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
  70. package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +7 -13
  71. package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +12 -14
  72. package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
  73. package/core/lib/lantern/metrics/TotalBlockingTime.d.ts +25 -0
  74. package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +13 -16
  75. package/core/lib/lantern/metrics/__snapshots__/first-contentful-paint-test.js.snap +11 -0
  76. package/core/lib/lantern/metrics/__snapshots__/interactive-test.js.snap +17 -0
  77. package/core/lib/lantern/metrics/metrics.d.ts +9 -0
  78. package/core/lib/lantern/metrics/metrics.js +16 -0
  79. package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +5 -5
  80. package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +3 -3
  81. package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
  82. package/core/lib/lantern/simulation/Constants.d.ts +52 -0
  83. package/core/lib/lantern/simulation/Constants.js +48 -0
  84. package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +2 -2
  85. package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +1 -1
  86. package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
  87. package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +8 -8
  88. package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +3 -3
  89. package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
  90. package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
  91. package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
  92. package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +13 -15
  93. package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +29 -30
  94. package/core/lib/lantern/simulation/Simulator.test.js +434 -0
  95. package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
  96. package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
  97. package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
  98. package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
  99. package/core/lib/lantern/simulation/simulation.d.ts +21 -0
  100. package/core/lib/lantern/simulation/simulation.js +28 -0
  101. package/core/lib/lantern/types/lantern.d.ts +81 -9
  102. package/core/lib/lantern-trace-saver.d.ts +4 -4
  103. package/core/lib/lantern-trace-saver.js +3 -3
  104. package/core/lib/navigation-error.js +3 -3
  105. package/core/lib/network-recorder.js +2 -2
  106. package/core/lib/network-request.d.ts +1 -1
  107. package/core/lib/network-request.js +1 -1
  108. package/package.json +5 -5
  109. package/tsconfig.json +10 -8
  110. package/types/artifacts.d.ts +3 -10
  111. package/types/gatherer.d.ts +1 -1
  112. package/core/lib/lantern/cpu-node.d.ts +0 -44
  113. package/core/lib/lantern/metrics/interactive.d.ts +0 -26
  114. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +0 -19
  115. package/core/lib/lantern/metrics/max-potential-fid.d.ts +0 -30
  116. package/core/lib/lantern/metrics/total-blocking-time.d.ts +0 -31
  117. /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
  118. /package/core/lib/lantern/{tbt-utils.js → TBTUtils.js} +0 -0
@@ -0,0 +1,374 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2017 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import assert from 'assert/strict';
8
+
9
+ import * as Lantern from '../lantern.js';
10
+
11
+ const {TcpConnection} = Lantern.Simulation;
12
+
13
+ describe('DependencyGraph/Simulator/TcpConnection', () => {
14
+ describe('#constructor', () => {
15
+ it('should create the connection', () => {
16
+ const rtt = 150;
17
+ const throughput = 1600 * 1024;
18
+ const connection = new TcpConnection(rtt, throughput);
19
+ assert.ok(connection);
20
+ assert.equal(connection._rtt, rtt);
21
+ });
22
+ });
23
+
24
+ describe('#maximumSaturatedConnections', () => {
25
+ it('should compute number of supported simulated requests', () => {
26
+ const availableThroughput = 1460 * 8 * 10; // 10 TCP segments/second
27
+ assert.equal(TcpConnection.maximumSaturatedConnections(100, availableThroughput), 1);
28
+ assert.equal(TcpConnection.maximumSaturatedConnections(300, availableThroughput), 3);
29
+ assert.equal(TcpConnection.maximumSaturatedConnections(1000, availableThroughput), 10);
30
+ });
31
+ });
32
+
33
+ describe('.setWarmed', () => {
34
+ it('adjusts the time to download appropriately', () => {
35
+ const connection = new TcpConnection(100, Infinity);
36
+ assert.equal(connection.simulateDownloadUntil(0).timeElapsed, 300);
37
+ connection.setWarmed(true);
38
+ assert.equal(connection.simulateDownloadUntil(0).timeElapsed, 100);
39
+ });
40
+ });
41
+
42
+ describe('.setCongestionWindow', () => {
43
+ it('adjusts the time to download appropriately', () => {
44
+ const connection = new TcpConnection(100, Infinity);
45
+ assert.deepEqual(connection.simulateDownloadUntil(50000), {
46
+ bytesDownloaded: 50000,
47
+ extraBytesDownloaded: 0,
48
+ congestionWindow: 40,
49
+ roundTrips: 5,
50
+ timeElapsed: 500,
51
+ connectionTiming: {
52
+ connectionTime: 250,
53
+ dnsResolutionTime: 0,
54
+ sslTime: 100,
55
+ timeToFirstByte: 300,
56
+ },
57
+ });
58
+ connection.setCongestionWindow(40); // will download all in one round trip
59
+ assert.deepEqual(connection.simulateDownloadUntil(50000), {
60
+ bytesDownloaded: 50000,
61
+ extraBytesDownloaded: 0,
62
+ congestionWindow: 40,
63
+ roundTrips: 3,
64
+ timeElapsed: 300,
65
+ connectionTiming: {
66
+ connectionTime: 250,
67
+ dnsResolutionTime: 0,
68
+ sslTime: 100,
69
+ timeToFirstByte: 300,
70
+ },
71
+ });
72
+ });
73
+ });
74
+
75
+ describe('.setH2OverflowBytesDownloaded', () => {
76
+ it('adjusts the time to download appropriately for H2 connections', () => {
77
+ const connection = new TcpConnection(100, Infinity, 0, true, true);
78
+ connection.setWarmed(true);
79
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
80
+ connection.setH2OverflowBytesDownloaded(20000);
81
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 100);
82
+ connection.setH2OverflowBytesDownloaded(50000);
83
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 0);
84
+ });
85
+
86
+ it('does not adjust the time to download for non-H2 connections', () => {
87
+ const connection = new TcpConnection(100, Infinity, 0, true, false);
88
+ connection.setWarmed(true);
89
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
90
+ connection.setH2OverflowBytesDownloaded(20000);
91
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
92
+ connection.setH2OverflowBytesDownloaded(50000);
93
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
94
+ });
95
+ });
96
+
97
+ describe('.simulateDownloadUntil', () => {
98
+ describe('when maximumTime is not set', () => {
99
+ it('should provide the correct values small payload non-SSL', () => {
100
+ const connection = new TcpConnection(100, Infinity, 0, false);
101
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
102
+ bytesDownloaded: 7300,
103
+ extraBytesDownloaded: 0,
104
+ congestionWindow: 10,
105
+ roundTrips: 2,
106
+ timeElapsed: 200,
107
+ connectionTiming: {
108
+ connectionTime: 150,
109
+ dnsResolutionTime: 0,
110
+ sslTime: undefined, // non-SSL
111
+ timeToFirstByte: 200,
112
+ },
113
+ });
114
+ });
115
+
116
+ it('should provide the correct values small payload SSL', () => {
117
+ const connection = new TcpConnection(100, Infinity, 0, true);
118
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
119
+ bytesDownloaded: 7300,
120
+ extraBytesDownloaded: 0,
121
+ congestionWindow: 10,
122
+ roundTrips: 3,
123
+ timeElapsed: 300,
124
+ connectionTiming: {
125
+ connectionTime: 250,
126
+ dnsResolutionTime: 0,
127
+ sslTime: 100,
128
+ timeToFirstByte: 300,
129
+ },
130
+ });
131
+ });
132
+
133
+ it('should provide the correct values small payload H2', () => {
134
+ const connection = new TcpConnection(100, Infinity, 0, true, true);
135
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
136
+ bytesDownloaded: 7300,
137
+ extraBytesDownloaded: 7300,
138
+ congestionWindow: 10,
139
+ roundTrips: 3,
140
+ timeElapsed: 300,
141
+ connectionTiming: {
142
+ connectionTime: 250,
143
+ dnsResolutionTime: 0,
144
+ sslTime: 100,
145
+ timeToFirstByte: 300,
146
+ },
147
+ });
148
+ });
149
+
150
+ it('should provide the correct values response time', () => {
151
+ const responseTime = 78;
152
+ const connection = new TcpConnection(100, Infinity, responseTime, true);
153
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
154
+ bytesDownloaded: 7300,
155
+ extraBytesDownloaded: 0,
156
+ congestionWindow: 10,
157
+ roundTrips: 3,
158
+ timeElapsed: 300 + responseTime,
159
+ connectionTiming: {
160
+ connectionTime: 250,
161
+ dnsResolutionTime: 0,
162
+ sslTime: 100,
163
+ timeToFirstByte: 378,
164
+ },
165
+ });
166
+ });
167
+
168
+ it('should provide the correct values large payload', () => {
169
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
170
+ const bytesToDownload = 10 * 1000 * 1000; // 10 mb
171
+ assert.deepEqual(connection.simulateDownloadUntil(bytesToDownload), {
172
+ bytesDownloaded: bytesToDownload,
173
+ extraBytesDownloaded: 0,
174
+ congestionWindow: 68,
175
+ roundTrips: 105,
176
+ timeElapsed: 10500,
177
+ connectionTiming: {
178
+ connectionTime: 250,
179
+ dnsResolutionTime: 0,
180
+ sslTime: 100,
181
+ timeToFirstByte: 300,
182
+ },
183
+ });
184
+ });
185
+
186
+ it('should provide the correct values resumed small payload', () => {
187
+ const connection = new TcpConnection(100, Infinity, 0, true);
188
+ assert.deepEqual(connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 250}), {
189
+ bytesDownloaded: 7300,
190
+ extraBytesDownloaded: 0,
191
+ congestionWindow: 10,
192
+ roundTrips: 3,
193
+ timeElapsed: 50,
194
+ connectionTiming: {
195
+ connectionTime: 250,
196
+ dnsResolutionTime: 0,
197
+ sslTime: 100,
198
+ timeToFirstByte: 300,
199
+ },
200
+ });
201
+ });
202
+
203
+ it('should provide the correct values resumed small payload H2', () => {
204
+ const connection = new TcpConnection(100, Infinity, 0, true, true);
205
+ connection.setWarmed(true);
206
+ connection.setH2OverflowBytesDownloaded(10000);
207
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
208
+ bytesDownloaded: 0,
209
+ extraBytesDownloaded: 2700, // 10000 - 7300
210
+ congestionWindow: 10,
211
+ roundTrips: 0,
212
+ timeElapsed: 0,
213
+ connectionTiming: {
214
+ timeToFirstByte: 0,
215
+ },
216
+ });
217
+ });
218
+
219
+ it('should provide the correct values resumed large payload', () => {
220
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
221
+ const bytesToDownload = 5 * 1000 * 1000; // 5 mb
222
+ connection.setCongestionWindow(68);
223
+ assert.deepEqual(
224
+ connection.simulateDownloadUntil(bytesToDownload, {timeAlreadyElapsed: 5234}),
225
+ {
226
+ bytesDownloaded: bytesToDownload,
227
+ extraBytesDownloaded: 0,
228
+ congestionWindow: 68,
229
+ roundTrips: 51, // 5 mb / (1460 * 68)
230
+ timeElapsed: 5100,
231
+ connectionTiming: {
232
+ connectionTime: 250,
233
+ dnsResolutionTime: 0,
234
+ sslTime: 100,
235
+ timeToFirstByte: 300,
236
+ },
237
+ }
238
+ );
239
+ });
240
+ });
241
+
242
+ describe('when maximumTime is set', () => {
243
+ it('should provide the correct values less than TTFB', () => {
244
+ const connection = new TcpConnection(100, Infinity, 0, false);
245
+ assert.deepEqual(
246
+ connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 68}),
247
+ {
248
+ bytesDownloaded: 7300,
249
+ extraBytesDownloaded: 0,
250
+ congestionWindow: 10,
251
+ roundTrips: 2,
252
+ timeElapsed: 200,
253
+ connectionTiming: {
254
+ connectionTime: 150,
255
+ dnsResolutionTime: 0,
256
+ sslTime: undefined, // non-SSL
257
+ timeToFirstByte: 200,
258
+ },
259
+ }
260
+ );
261
+ });
262
+
263
+ it('should provide the correct values just over TTFB', () => {
264
+ const connection = new TcpConnection(100, Infinity, 0, false);
265
+ assert.deepEqual(
266
+ connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 250}),
267
+ {
268
+ bytesDownloaded: 7300,
269
+ extraBytesDownloaded: 0,
270
+ congestionWindow: 10,
271
+ roundTrips: 2,
272
+ timeElapsed: 200,
273
+ connectionTiming: {
274
+ connectionTime: 150,
275
+ dnsResolutionTime: 0,
276
+ sslTime: undefined, // non-SSL
277
+ timeToFirstByte: 200,
278
+ },
279
+ }
280
+ );
281
+ });
282
+
283
+ it('should provide the correct values with already elapsed', () => {
284
+ const connection = new TcpConnection(100, Infinity, 0, false);
285
+ assert.deepEqual(
286
+ connection.simulateDownloadUntil(7300, {
287
+ timeAlreadyElapsed: 75,
288
+ maximumTimeToElapse: 250,
289
+ }),
290
+ {
291
+ bytesDownloaded: 7300,
292
+ extraBytesDownloaded: 0,
293
+ congestionWindow: 10,
294
+ roundTrips: 2,
295
+ timeElapsed: 125,
296
+ connectionTiming: {
297
+ connectionTime: 150,
298
+ dnsResolutionTime: 0,
299
+ sslTime: undefined, // non-SSL
300
+ timeToFirstByte: 200,
301
+ },
302
+ }
303
+ );
304
+ });
305
+
306
+ it('should provide the correct values large payloads', () => {
307
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
308
+ const bytesToDownload = 10 * 1000 * 1000; // 10 mb
309
+ assert.deepEqual(
310
+ connection.simulateDownloadUntil(bytesToDownload, {
311
+ timeAlreadyElapsed: 500,
312
+ maximumTimeToElapse: 740,
313
+ }),
314
+ {
315
+ bytesDownloaded: 683280, // should be less than 68 * 1460 * 8
316
+ extraBytesDownloaded: 0,
317
+ congestionWindow: 68,
318
+ roundTrips: 8,
319
+ timeElapsed: 800, // skips the handshake because time already elapsed
320
+ connectionTiming: {
321
+ connectionTime: 250,
322
+ dnsResolutionTime: 0,
323
+ sslTime: 100,
324
+ timeToFirstByte: 300,
325
+ },
326
+ }
327
+ );
328
+ });
329
+
330
+ it('should all add up', () => {
331
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
332
+ const bytesToDownload = 10 * 1000 * 1000; // 10 mb
333
+ const firstStoppingPoint = 5234;
334
+ const secondStoppingPoint = 315;
335
+ const thirdStoppingPoint = 10500 - firstStoppingPoint - secondStoppingPoint;
336
+
337
+ const firstSegment = connection.simulateDownloadUntil(bytesToDownload, {
338
+ timeAlreadyElapsed: 0,
339
+ maximumTimeToElapse: firstStoppingPoint,
340
+ });
341
+ const firstOvershoot = firstSegment.timeElapsed - firstStoppingPoint;
342
+
343
+ connection.setCongestionWindow(firstSegment.congestionWindow);
344
+ const secondSegment = connection.simulateDownloadUntil(
345
+ bytesToDownload - firstSegment.bytesDownloaded,
346
+ {
347
+ timeAlreadyElapsed: firstSegment.timeElapsed,
348
+ maximumTimeToElapse: secondStoppingPoint - firstOvershoot,
349
+ }
350
+ );
351
+ const secondOvershoot = firstOvershoot + secondSegment.timeElapsed - secondStoppingPoint;
352
+
353
+ connection.setCongestionWindow(secondSegment.congestionWindow);
354
+ const thirdSegment = connection.simulateDownloadUntil(
355
+ bytesToDownload - firstSegment.bytesDownloaded - secondSegment.bytesDownloaded,
356
+ {timeAlreadyElapsed: firstSegment.timeElapsed + secondSegment.timeElapsed}
357
+ );
358
+ const thirdOvershoot = secondOvershoot + thirdSegment.timeElapsed - thirdStoppingPoint;
359
+
360
+ assert.equal(thirdOvershoot, 0);
361
+ assert.equal(
362
+ firstSegment.bytesDownloaded +
363
+ secondSegment.bytesDownloaded +
364
+ thirdSegment.bytesDownloaded,
365
+ bytesToDownload
366
+ );
367
+ assert.equal(
368
+ firstSegment.timeElapsed + secondSegment.timeElapsed + thirdSegment.timeElapsed,
369
+ 10500
370
+ );
371
+ });
372
+ });
373
+ });
374
+ });
@@ -1,4 +1,4 @@
1
- export type ConnectionTiming = import('./simulator-timing-map.js').ConnectionTiming;
1
+ export type ConnectionTiming = import('./SimulationTimingMap.js').ConnectionTiming;
2
2
  export type DownloadOptions = {
3
3
  dnsResolutionTime?: number | undefined;
4
4
  timeAlreadyElapsed?: number | undefined;
@@ -86,4 +86,4 @@ export class TcpConnection {
86
86
  */
87
87
  simulateDownloadUntil(bytesToDownload: number, options?: DownloadOptions | undefined): DownloadResults;
88
88
  }
89
- //# sourceMappingURL=tcp-connection.d.ts.map
89
+ //# sourceMappingURL=TcpConnection.d.ts.map
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /** @typedef {import('./simulator-timing-map.js').ConnectionTiming} ConnectionTiming */
7
+ /** @typedef {import('./SimulationTimingMap.js').ConnectionTiming} ConnectionTiming */
8
8
 
9
9
  const INITIAL_CONGESTION_WINDOW = 10;
10
10
  const TCP_SEGMENT_SIZE = 1460;
@@ -0,0 +1,21 @@
1
+ export { ConnectionPool } from "./ConnectionPool.js";
2
+ export { Constants } from "./Constants.js";
3
+ export { DNSCache } from "./DNSCache.js";
4
+ export { NetworkAnalyzer } from "./NetworkAnalyzer.js";
5
+ export { Simulator } from "./Simulator.js";
6
+ export { SimulatorTimingMap } from "./SimulationTimingMap.js";
7
+ export { TcpConnection } from "./TcpConnection.js";
8
+ export type GraphNetworkNode<T = any> = Lantern.Simulation.GraphNetworkNode<T>;
9
+ export type GraphNode<T = any> = Lantern.Simulation.GraphNode<T>;
10
+ export type Result<T = any> = Lantern.Simulation.Result<T>;
11
+ export type GraphCPUNode = Lantern.Simulation.GraphCPUNode;
12
+ export type MetricCoefficients = Lantern.Simulation.MetricCoefficients;
13
+ export type MetricComputationDataInput = Lantern.Simulation.MetricComputationDataInput;
14
+ export type NodeTiming = Lantern.Simulation.NodeTiming;
15
+ export type Options = Lantern.Simulation.Options;
16
+ export type PrecomputedLanternData = Lantern.Simulation.PrecomputedLanternData;
17
+ export type ProcessedNavigation = Lantern.Simulation.ProcessedNavigation;
18
+ export type Settings = Lantern.Simulation.Settings;
19
+ export type URL = Lantern.Simulation.URL;
20
+ import * as Lantern from '../types/lantern.js';
21
+ //# sourceMappingURL=simulation.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2024 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import * as Lantern from '../types/lantern.js';
8
+
9
+ export {ConnectionPool} from './ConnectionPool.js';
10
+ export {Constants} from './Constants.js';
11
+ export {DNSCache} from './DNSCache.js';
12
+ export {NetworkAnalyzer} from './NetworkAnalyzer.js';
13
+ export {Simulator} from './Simulator.js';
14
+ export {SimulatorTimingMap} from './SimulationTimingMap.js';
15
+ export {TcpConnection} from './TcpConnection.js';
16
+
17
+ /** @template [T=any] @typedef {Lantern.Simulation.GraphNetworkNode<T>} GraphNetworkNode */
18
+ /** @template [T=any] @typedef {Lantern.Simulation.GraphNode<T>} GraphNode */
19
+ /** @template [T=any] @typedef {Lantern.Simulation.Result<T>} Result */
20
+ /** @typedef {Lantern.Simulation.GraphCPUNode} GraphCPUNode */
21
+ /** @typedef {Lantern.Simulation.MetricCoefficients} MetricCoefficients */
22
+ /** @typedef {Lantern.Simulation.MetricComputationDataInput} MetricComputationDataInput */
23
+ /** @typedef {Lantern.Simulation.NodeTiming} NodeTiming */
24
+ /** @typedef {Lantern.Simulation.Options} Options */
25
+ /** @typedef {Lantern.Simulation.PrecomputedLanternData} PrecomputedLanternData */
26
+ /** @typedef {Lantern.Simulation.ProcessedNavigation} ProcessedNavigation */
27
+ /** @typedef {Lantern.Simulation.Settings} Settings */
28
+ /** @typedef {Lantern.Simulation.URL} URL */
@@ -4,7 +4,58 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import * as LH from '../../../../types/lh.js';
7
+ import * as Protocol from '@paulirish/trace_engine/generated/protocol.js';
8
+
9
+ declare module Util {
10
+ /** An object with the keys in the union K mapped to themselves as values. */
11
+ type SelfMap<K extends string> = {
12
+ [P in K]: P;
13
+ };
14
+ }
15
+
16
+ type TraceEvent = {
17
+ name: string;
18
+ cat: string;
19
+ args: {
20
+ name?: string;
21
+ fileName?: string;
22
+ snapshot?: string;
23
+ sync_id?: string;
24
+ beginData?: {
25
+ frame?: string;
26
+ startLine?: number;
27
+ url?: string;
28
+ };
29
+ data?: {
30
+ frame?: string;
31
+ readyState?: number;
32
+ stackTrace?: {
33
+ url: string
34
+ }[];
35
+ url?: string;
36
+ };
37
+ };
38
+ pid: number;
39
+ tid: number;
40
+ /** Timestamp of the event in microseconds. */
41
+ ts: number;
42
+ dur: number;
43
+ }
44
+ type Trace = {traceEvents: TraceEvent[]};
45
+ type ResourcePriority = ('VeryLow' | 'Low' | 'Medium' | 'High' | 'VeryHigh');
46
+ type ResourceType = ('Document' | 'Stylesheet' | 'Image' | 'Media' | 'Font' | 'Script' | 'TextTrack' | 'XHR' | 'Fetch' | 'Prefetch' | 'EventSource' | 'WebSocket' | 'Manifest' | 'SignedExchange' | 'Ping' | 'CSPViolationReport' | 'Preflight' | 'Other');
47
+ type InitiatorType = ('parser' | 'script' | 'preload' | 'SignedExchange' | 'preflight' | 'other');
48
+ type ResourceTiming = Protocol.Network.ResourceTiming;
49
+ type CallStack = {
50
+ callFrames: Array<{
51
+ scriptId: string;
52
+ url: string;
53
+ lineNumber: number;
54
+ columnNumber: number;
55
+ functionName: string;
56
+ }>;
57
+ parent?: CallStack;
58
+ }
8
59
 
9
60
  type ParsedURL = {
10
61
  /**
@@ -80,28 +131,49 @@ export class NetworkRequest<T = any> {
80
131
  redirectSource: NetworkRequest<T> | undefined;
81
132
  /** The network request that this one redirected to */
82
133
  redirectDestination: NetworkRequest<T> | undefined;
83
- initiator: LH.Crdp.Network.Initiator;
134
+ // TODO: can't use Protocol.Network.Initiator because of type mismatch in Lighthouse initiator.
135
+ initiator: {
136
+ type: InitiatorType;
137
+ url?: string;
138
+ stack?: CallStack;
139
+ };
84
140
  initiatorRequest: NetworkRequest<T> | undefined;
85
141
  /** The chain of network requests that redirected to this one */
86
142
  redirects: NetworkRequest[] | undefined;
87
- timing: LH.Crdp.Network.ResourceTiming | undefined;
143
+ timing: Protocol.Network.ResourceTiming | undefined;
88
144
  /**
89
145
  * Optional value for how long the server took to respond to this request.
90
146
  * When not provided, the server response time is derived from the timing object.
91
147
  */
92
148
  serverResponseTime?: number;
93
- resourceType: LH.Crdp.Network.ResourceType | undefined;
149
+ resourceType: ResourceType | undefined;
94
150
  mimeType: string;
95
- priority: LH.Crdp.Network.ResourcePriority;
151
+ priority: ResourcePriority;
96
152
  frameId: string | undefined;
97
153
  fromWorker: boolean;
98
154
  }
99
155
 
156
+ interface MetricResult<T = any> {
157
+ timing: number;
158
+ timestamp?: never;
159
+ optimisticEstimate: Simulation.Result<T>;
160
+ pessimisticEstimate: Simulation.Result<T>;
161
+ optimisticGraph: Simulation.GraphNode<T>;
162
+ pessimisticGraph: Simulation.GraphNode<T>;
163
+ }
164
+
100
165
  export namespace Simulation {
101
- type GraphNode<T> = import('../base-node.js').Node<T>;
102
- type GraphNetworkNode<T> = import('../network-node.js').NetworkNode<T>;
103
- type GraphCPUNode = import('../cpu-node.js').CPUNode;
104
- type Simulator<T> = import('../simulator/simulator.js').Simulator<T>;
166
+ type URL = {
167
+ /** URL of the initially requested URL */
168
+ requestedUrl?: string;
169
+ /** URL of the last document request */
170
+ mainDocumentUrl?: string;
171
+ };
172
+
173
+ type GraphNode<T> = import('../BaseNode.js').Node<T>;
174
+ type GraphNetworkNode<T> = import('../NetworkNode.js').NetworkNode<T>;
175
+ type GraphCPUNode = import('../CpuNode.js').CPUNode;
176
+ type Simulator<T> = import('../simulation/Simulator.js').Simulator<T>;
105
177
 
106
178
  interface MetricCoefficients {
107
179
  intercept: number;
@@ -3,15 +3,15 @@ declare namespace _default {
3
3
  export { convertNodeTimingsToTrace };
4
4
  }
5
5
  export default _default;
6
- export type Node = import('./lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>;
7
- export type CompleteNodeTiming = import('./lantern/simulator/simulator.js').CompleteNodeTiming;
6
+ export type Node = import('./lantern/BaseNode.js').Node<LH.Artifacts.NetworkRequest>;
7
+ export type CompleteNodeTiming = import('./lantern/simulation/Simulator.js').CompleteNodeTiming;
8
8
  /**
9
9
  * @license
10
10
  * Copyright 2018 Google LLC
11
11
  * SPDX-License-Identifier: Apache-2.0
12
12
  */
13
- /** @typedef {import('./lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
14
- /** @typedef {import('./lantern/simulator/simulator.js').CompleteNodeTiming} CompleteNodeTiming */
13
+ /** @typedef {import('./lantern/BaseNode.js').Node<LH.Artifacts.NetworkRequest>} Node */
14
+ /** @typedef {import('./lantern/simulation/Simulator.js').CompleteNodeTiming} CompleteNodeTiming */
15
15
  /**
16
16
  * @param {Map<Node, CompleteNodeTiming>} nodeTimings
17
17
  * @return {LH.Trace}
@@ -4,8 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /** @typedef {import('./lantern/base-node.js').Node<LH.Artifacts.NetworkRequest>} Node */
8
- /** @typedef {import('./lantern/simulator/simulator.js').CompleteNodeTiming} CompleteNodeTiming */
7
+ /** @typedef {import('./lantern/BaseNode.js').Node<LH.Artifacts.NetworkRequest>} Node */
8
+ /** @typedef {import('./lantern/simulation/Simulator.js').CompleteNodeTiming} CompleteNodeTiming */
9
9
 
10
10
  /**
11
11
  * @param {Map<Node, CompleteNodeTiming>} nodeTimings
@@ -116,7 +116,7 @@ function convertNodeTimingsToTrace(nodeTimings) {
116
116
  const ts = eventTs + (event.ts - nestedBaseTs) * multiplier;
117
117
  const newEvent = {...event, ...{pid: baseEvent.pid, tid: baseEvent.tid}, ts};
118
118
  if (event.dur) newEvent.dur = event.dur * multiplier;
119
- events.push(newEvent);
119
+ events.push(/** @type {LH.TraceEvent} */(newEvent));
120
120
  }
121
121
 
122
122
  return events;
@@ -4,8 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ import * as Lantern from './lantern/lantern.js';
7
8
  import {LighthouseError} from './lh-error.js';
8
- import {NetworkAnalyzer} from './lantern/simulator/network-analyzer.js';
9
9
  import {NetworkRequest} from './network-request.js';
10
10
  import * as i18n from '../lib/i18n/i18n.js';
11
11
 
@@ -131,7 +131,7 @@ function getNonHtmlError(finalRecord) {
131
131
  function getPageLoadError(navigationError, context) {
132
132
  const {url, networkRecords} = context;
133
133
  /** @type {LH.Artifacts.NetworkRequest|undefined} */
134
- let mainRecord = NetworkAnalyzer.findResourceForUrl(networkRecords, url);
134
+ let mainRecord = Lantern.Simulation.NetworkAnalyzer.findResourceForUrl(networkRecords, url);
135
135
 
136
136
  // If the url doesn't give us a network request, it's possible we landed on a chrome-error:// page
137
137
  // In this case, just get the first document request.
@@ -149,7 +149,7 @@ function getPageLoadError(navigationError, context) {
149
149
  // MIME Type is only set on the final redirected document request. Use this for the HTML check instead of root.
150
150
  let finalRecord;
151
151
  if (mainRecord) {
152
- finalRecord = NetworkAnalyzer.resolveRedirects(mainRecord);
152
+ finalRecord = Lantern.Simulation.NetworkAnalyzer.resolveRedirects(mainRecord);
153
153
  } else {
154
154
  // We have no network requests to process, use the navError
155
155
  return navigationError;
@@ -9,8 +9,8 @@ import {EventEmitter} from 'events';
9
9
  import log from 'lighthouse-logger';
10
10
 
11
11
  import * as LH from '../../types/lh.js';
12
+ import * as Lantern from './lantern/lantern.js';
12
13
  import {NetworkRequest} from './network-request.js';
13
- import {PageDependencyGraph} from '../lib/lantern/page-dependency-graph.js';
14
14
 
15
15
  /**
16
16
  * @typedef {{
@@ -253,7 +253,7 @@ class NetworkRecorder extends RequestEventEmitter {
253
253
  return record.redirectSource;
254
254
  }
255
255
 
256
- const initiatorURL = PageDependencyGraph.getNetworkInitiators(record)[0];
256
+ const initiatorURL = Lantern.PageDependencyGraph.getNetworkInitiators(record)[0];
257
257
  let candidates = recordsByURL.get(initiatorURL) || [];
258
258
  // The (valid) initiator must come before the initiated request.
259
259
  candidates = candidates.filter(c => {
@@ -285,7 +285,7 @@ export namespace NetworkRequest {
285
285
  /** @type {LH.Util.SelfMap<LH.Crdp.Network.ResourceType>} */
286
286
  export const RESOURCE_TYPES: LH.Util.SelfMap<LH.Crdp.Network.ResourceType>;
287
287
  import * as LH from '../../types/lh.js';
288
- import * as Lantern from './lantern/types/lantern.js';
288
+ import * as Lantern from './lantern/lantern.js';
289
289
  declare const HEADER_TCP: "X-TCPMs";
290
290
  declare const HEADER_SSL: "X-SSLMs";
291
291
  declare const HEADER_REQ: "X-RequestMs";
@@ -53,7 +53,7 @@
53
53
  */
54
54
 
55
55
  import * as LH from '../../types/lh.js';
56
- import * as Lantern from './lantern/types/lantern.js';
56
+ import * as Lantern from './lantern/lantern.js';
57
57
  import UrlUtils from './url-utils.js';
58
58
 
59
59
  // Lightrider X-Header names for timing information.