lighthouse 12.0.0-dev.20240611 → 12.0.0-dev.20240613
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/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +2 -2
- package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
- package/core/audits/byte-efficiency/render-blocking-resources.js +4 -4
- package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
- package/core/audits/dobetterweb/uses-http2.js +2 -2
- package/core/audits/long-tasks.d.ts +1 -1
- package/core/audits/long-tasks.js +1 -1
- package/core/audits/prioritize-lcp-image.d.ts +1 -1
- package/core/computed/document-urls.js +3 -2
- package/core/computed/load-simulator.d.ts +4 -4
- package/core/computed/load-simulator.js +3 -3
- package/core/computed/main-resource.js +3 -2
- package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
- package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
- package/core/computed/metrics/lantern-interactive.d.ts +4 -4
- package/core/computed/metrics/lantern-interactive.js +3 -3
- package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
- package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
- package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
- package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
- package/core/computed/metrics/lantern-metric.d.ts +4 -3
- package/core/computed/metrics/lantern-metric.js +4 -4
- package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
- package/core/computed/metrics/lantern-speed-index.js +3 -3
- package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
- package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
- package/core/computed/metrics/total-blocking-time.js +3 -1
- package/core/computed/network-analysis.js +2 -2
- package/core/computed/page-dependency-graph.d.ts +2 -2
- package/core/computed/page-dependency-graph.js +6 -6
- package/core/computed/tbt-impact-tasks.js +3 -2
- package/core/config/constants.js +1 -1
- package/core/lib/asset-saver.js +2 -2
- package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
- package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
- package/core/lib/lantern/BaseNode.test.js +385 -0
- package/core/lib/lantern/{cpu-node.d.ts → CpuNode.d.ts} +8 -9
- package/core/lib/lantern/{cpu-node.js → CpuNode.js} +4 -5
- package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
- package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +17 -17
- package/core/lib/lantern/{metric.js → Metric.js} +10 -12
- package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +4 -5
- package/core/lib/lantern/{network-node.js → NetworkNode.js} +4 -5
- package/core/lib/lantern/{page-dependency-graph.d.ts → PageDependencyGraph.d.ts} +5 -5
- package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +11 -10
- package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
- package/core/lib/lantern/{tbt-utils.d.ts → TBTUtils.d.ts} +1 -1
- package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
- package/core/lib/lantern/TBTUtils.test.js +130 -0
- package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts} +3 -3
- package/core/lib/lantern/{trace-engine-computation-data.js → TraceEngineComputationData.js} +5 -7
- package/core/lib/lantern/lantern.d.ts +16 -46
- package/core/lib/lantern/lantern.js +16 -40
- package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
- package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +8 -10
- package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
- package/core/lib/lantern/metrics/{interactive.d.ts → Interactive.d.ts} +4 -5
- package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +10 -13
- package/core/lib/lantern/metrics/Interactive.test.js +56 -0
- package/core/lib/lantern/metrics/{largest-contentful-paint.d.ts → LargestContentfulPaint.d.ts} +5 -6
- package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +9 -12
- package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
- package/core/lib/lantern/metrics/{max-potential-fid.d.ts → MaxPotentialFID.d.ts} +5 -6
- package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +8 -9
- package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
- package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
- package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +5 -6
- package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +7 -9
- package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
- package/core/lib/lantern/metrics/{total-blocking-time.d.ts → TotalBlockingTime.d.ts} +5 -6
- package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +9 -12
- package/core/lib/lantern/metrics/__snapshots__/first-contentful-paint-test.js.snap +11 -0
- package/core/lib/lantern/metrics/__snapshots__/interactive-test.js.snap +17 -0
- package/core/lib/lantern/metrics/metrics.d.ts +9 -0
- package/core/lib/lantern/metrics/metrics.js +16 -0
- package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +5 -5
- package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +3 -3
- package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
- package/core/lib/lantern/simulation/Constants.d.ts +52 -0
- package/core/lib/lantern/simulation/Constants.js +48 -0
- package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +2 -2
- package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +1 -1
- package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
- package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +2 -2
- package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +1 -1
- package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
- package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
- package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
- package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +13 -15
- package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +25 -26
- package/core/lib/lantern/simulation/Simulator.test.js +434 -0
- package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
- package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
- package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
- package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
- package/core/lib/lantern/simulation/simulation.d.ts +21 -0
- package/core/lib/lantern/simulation/simulation.js +28 -0
- package/core/lib/lantern/types/lantern.d.ts +5 -5
- package/core/lib/lantern-trace-saver.d.ts +4 -4
- package/core/lib/lantern-trace-saver.js +2 -2
- package/core/lib/navigation-error.js +3 -3
- package/core/lib/network-recorder.js +2 -2
- package/core/lib/network-request.d.ts +1 -1
- package/core/lib/network-request.js +1 -1
- package/package.json +2 -2
- package/tsconfig.json +10 -8
- package/types/artifacts.d.ts +3 -4
- package/types/gatherer.d.ts +1 -1
- /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
- /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('./
|
|
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=
|
|
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('./
|
|
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 */
|
|
@@ -153,7 +153,7 @@ export class NetworkRequest<T = any> {
|
|
|
153
153
|
fromWorker: boolean;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
interface
|
|
156
|
+
interface MetricResult<T = any> {
|
|
157
157
|
timing: number;
|
|
158
158
|
timestamp?: never;
|
|
159
159
|
optimisticEstimate: Simulation.Result<T>;
|
|
@@ -170,10 +170,10 @@ export namespace Simulation {
|
|
|
170
170
|
mainDocumentUrl?: string;
|
|
171
171
|
};
|
|
172
172
|
|
|
173
|
-
type GraphNode<T> = import('../
|
|
174
|
-
type GraphNetworkNode<T> = import('../
|
|
175
|
-
type GraphCPUNode = import('../
|
|
176
|
-
type Simulator<T> = import('../
|
|
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>;
|
|
177
177
|
|
|
178
178
|
interface MetricCoefficients {
|
|
179
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/
|
|
7
|
-
export type CompleteNodeTiming = import('./lantern/
|
|
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/
|
|
14
|
-
/** @typedef {import('./lantern/
|
|
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/
|
|
8
|
-
/** @typedef {import('./lantern/
|
|
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
|
|
@@ -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/
|
|
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/
|
|
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.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lighthouse",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "12.0.0-dev.
|
|
4
|
+
"version": "12.0.0-dev.20240613",
|
|
5
5
|
"description": "Automated auditing, performance metrics, and best practices for the web.",
|
|
6
6
|
"main": "./core/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
"@paulirish/trace_engine": "^0.0.23",
|
|
185
185
|
"@sentry/node": "^6.17.4",
|
|
186
186
|
"axe-core": "^4.9.1",
|
|
187
|
-
"chrome-launcher": "^1.1.
|
|
187
|
+
"chrome-launcher": "^1.1.2",
|
|
188
188
|
"configstore": "^5.0.1",
|
|
189
189
|
"csp_evaluator": "1.1.1",
|
|
190
190
|
"devtools-protocol": "0.0.1312386",
|
package/tsconfig.json
CHANGED
|
@@ -66,13 +66,15 @@
|
|
|
66
66
|
"core/test/lib/emulation-test.js",
|
|
67
67
|
"core/test/lib/i18n/i18n-test.js",
|
|
68
68
|
"core/test/lib/icons-test.js",
|
|
69
|
-
|
|
70
|
-
"core/
|
|
71
|
-
"core/
|
|
72
|
-
"core/
|
|
73
|
-
"core/
|
|
74
|
-
"core/
|
|
75
|
-
"core/
|
|
69
|
+
// TODO(15841): remove when importing Lantern from npm
|
|
70
|
+
"core/lib/lantern/BaseNode.test.js",
|
|
71
|
+
"core/lib/lantern/metrics/*.test.js",
|
|
72
|
+
"core/lib/lantern/PageDependencyGraph.test.js",
|
|
73
|
+
"core/lib/lantern/simulation/ConnectionPool.test.js",
|
|
74
|
+
"core/lib/lantern/simulation/DNSCache.test.js",
|
|
75
|
+
"core/lib/lantern/simulation/NetworkAnalyzer.test.js",
|
|
76
|
+
"core/lib/lantern/simulation/Simulator.test.js",
|
|
77
|
+
// ------ done TODO
|
|
76
78
|
"core/test/lib/lh-element-test.js",
|
|
77
79
|
"core/test/lib/lighthouse-compatibility-test.js",
|
|
78
80
|
"core/test/lib/manifest-parser-test.js",
|
|
@@ -109,6 +111,6 @@
|
|
|
109
111
|
"core/test/computed/metrics/interactive-test.js",
|
|
110
112
|
"core/test/computed/tbt-impact-tasks-test.js",
|
|
111
113
|
"core/test/fixtures/config-plugins/lighthouse-plugin-simple/plugin-simple.js",
|
|
112
|
-
"core/
|
|
114
|
+
"core/lib/lantern/metrics/MetricTestUtils.js",
|
|
113
115
|
],
|
|
114
116
|
}
|
package/types/artifacts.d.ts
CHANGED
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
import {Protocol as Crdp} from 'devtools-protocol/types/protocol.js';
|
|
8
8
|
import * as TraceEngine from '@paulirish/trace_engine';
|
|
9
|
-
import * as Lantern from '../core/lib/lantern/
|
|
9
|
+
import * as Lantern from '../core/lib/lantern/lantern.js';
|
|
10
10
|
import {LayoutShiftRootCausesData} from '@paulirish/trace_engine/models/trace/root-causes/LayoutShift.js';
|
|
11
11
|
|
|
12
12
|
import {parseManifest} from '../core/lib/manifest-parser.js';
|
|
13
|
-
import {Simulator} from '../core/lib/lantern/simulator/simulator.js';
|
|
14
13
|
import {LighthouseError} from '../core/lib/lh-error.js';
|
|
15
14
|
import {NetworkRequest as _NetworkRequest} from '../core/lib/network-request.js';
|
|
16
15
|
import speedline from 'speedline-core';
|
|
@@ -566,7 +565,7 @@ declare module Artifacts {
|
|
|
566
565
|
trace: Trace;
|
|
567
566
|
settings: Audit.Context['settings'];
|
|
568
567
|
gatherContext: Artifacts['GatherContext'];
|
|
569
|
-
simulator?: InstanceType<typeof Simulator>;
|
|
568
|
+
simulator?: InstanceType<typeof Lantern.Simulation.Simulator>;
|
|
570
569
|
URL: Artifacts['URL'];
|
|
571
570
|
}
|
|
572
571
|
|
|
@@ -592,7 +591,7 @@ declare module Artifacts {
|
|
|
592
591
|
throughput: number;
|
|
593
592
|
}
|
|
594
593
|
|
|
595
|
-
type LanternMetric = Lantern.
|
|
594
|
+
type LanternMetric = Lantern.Metrics.Result<Artifacts.NetworkRequest>;
|
|
596
595
|
|
|
597
596
|
type Speedline = speedline.Output<'speedIndex'>;
|
|
598
597
|
|
package/types/gatherer.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ import Config from './config.js';
|
|
|
17
17
|
import Result from './lhr/lhr.js';
|
|
18
18
|
import Protocol from './protocol.js';
|
|
19
19
|
import Puppeteer from './puppeteer.js';
|
|
20
|
-
import * as Lantern from '../core/lib/lantern/
|
|
20
|
+
import * as Lantern from '../core/lib/lantern/lantern.js';
|
|
21
21
|
|
|
22
22
|
type CrdpEvents = CrdpMappings.Events;
|
|
23
23
|
type CrdpCommands = CrdpMappings.Commands;
|
|
File without changes
|
|
File without changes
|