pagespeed-quest 0.5.0 → 0.6.2
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/build/adhoc.js +2 -2
- package/build/command.js +5 -12
- package/build/index.d.ts +1 -2
- package/build/index.js +2 -3
- package/build/inventory.js +18 -4
- package/build/lighthouse-digest.d.ts +12 -0
- package/build/lighthouse-digest.js +69 -0
- package/build/lighthouse.d.ts +2 -3
- package/build/lighthouse.js +24 -6
- package/build/loadshow.d.ts +0 -4
- package/build/loadshow.js +2 -21
- package/build/playback.d.ts +20 -21
- package/build/playback.js +46 -100
- package/build/recording.d.ts +22 -26
- package/build/recording.js +55 -90
- package/package.json +5 -5
- package/build/proxy.d.ts +0 -35
- package/build/proxy.js +0 -96
- package/build/throttling.d.ts +0 -33
- package/build/throttling.js +0 -89
package/build/adhoc.js
CHANGED
|
@@ -27,5 +27,5 @@ export async function playback() {
|
|
|
27
27
|
await execLighthouse({ url: proxy.entryUrl, proxyPort: proxy.port, headless: false, timeout: 60000 }, dependency);
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
30
|
+
recording().then(playback);
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRob2MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWRob2MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxHQUFHLE1BQU0sYUFBYSxDQUFBO0FBRTdCLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDaEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ2pELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRW5ELE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUE7QUFFbkMsTUFBTSxDQUFDLEtBQUssVUFBVSxTQUFTO0lBQzdCLE1BQU0sU0FBUyxHQUFHLCtCQUErQixDQUFBO0lBQ2pELGlEQUFpRDtJQUVqRCxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUE7SUFDN0MsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQTtJQUN4RSxNQUFNLGtCQUFrQixDQUN0QjtRQUNFLG1CQUFtQjtLQUNwQixFQUNELFVBQVUsRUFDVixLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUU7UUFDZCxLQUFLLENBQUMsUUFBUSxHQUFHLFNBQVMsQ0FBQTtRQUMxQixNQUFNLGNBQWMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDOUcsQ0FBQyxDQUNGLENBQUE7QUFDSCxDQUFDO0FBRUQsTUFBTSxDQUFDLEtBQUssVUFBVSxRQUFRO0lBQzVCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDeEUsTUFBTSxpQkFBaUIsQ0FDckI7UUFDRSxtQkFBbUI7S0FDcEIsRUFDRCxVQUFVLEVBQ1YsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO1FBQ2QsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFBO1FBQy9ELE1BQU0sY0FBYyxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssQ0FBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDbkgsQ0FBQyxDQUNGLENBQUE7QUFDSCxDQUFDO0FBRUQsU0FBUyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFBIn0=
|
package/build/command.js
CHANGED
|
@@ -33,7 +33,6 @@ function registerLighthouseCommands(main) {
|
|
|
33
33
|
url,
|
|
34
34
|
proxyPort: proxy.port,
|
|
35
35
|
deviceType,
|
|
36
|
-
noThrottling: true,
|
|
37
36
|
view: false,
|
|
38
37
|
artifactsDir,
|
|
39
38
|
headless: quiet,
|
|
@@ -88,10 +87,8 @@ function registerLoadshowCommands(main) {
|
|
|
88
87
|
});
|
|
89
88
|
const playback = loadshow.command('playback');
|
|
90
89
|
playback.description('Playback contents for loadshow');
|
|
91
|
-
playback.option('-l, --lighthouse', 'Loadshow with lighthouse throttling');
|
|
92
90
|
playback.action(async () => {
|
|
93
91
|
const inventoryRepository = new InventoryRepository(main.opts().inventory || './inventory');
|
|
94
|
-
const lighthouse = playback.opts().lighthouse;
|
|
95
92
|
const artifactsDir = loadshow.opts().artifacts || './artifacts';
|
|
96
93
|
const credit = loadshow.opts().credit || '';
|
|
97
94
|
const timeout = Number(loadshow.opts().timeout || '30000');
|
|
@@ -102,7 +99,6 @@ function registerLoadshowCommands(main) {
|
|
|
102
99
|
url: proxy.entryUrl,
|
|
103
100
|
proxyPort: proxy.port,
|
|
104
101
|
deviceType: proxy.deviceType,
|
|
105
|
-
syncLighthouseSpec: lighthouse,
|
|
106
102
|
artifactsDir,
|
|
107
103
|
credit,
|
|
108
104
|
timeout,
|
|
@@ -117,18 +113,15 @@ function registerProxyCommands(main) {
|
|
|
117
113
|
proxy.option('-r, --record <url>', 'Recording URL to start the proxy as recording mode', '');
|
|
118
114
|
proxy.action(async () => {
|
|
119
115
|
const inventoryRepository = new InventoryRepository(main.opts().inventory || './inventory');
|
|
120
|
-
const
|
|
121
|
-
inventoryRepository,
|
|
122
|
-
port: Number(proxy.opts().port || '8080'),
|
|
123
|
-
};
|
|
116
|
+
const port = Number(proxy.opts().port || '8080');
|
|
124
117
|
if (proxy.opts().record) {
|
|
125
118
|
const url = proxy.opts().record;
|
|
126
119
|
if (!url) {
|
|
127
120
|
throw new Error('Recording URL must be specified with --record option.');
|
|
128
121
|
}
|
|
129
122
|
// Recordingモード
|
|
130
|
-
await withRecordingProxy({
|
|
131
|
-
dependency.logger?.info(`Recording proxy started on port ${
|
|
123
|
+
await withRecordingProxy({ inventoryRepository, port, entryUrl: url }, dependency, async () => {
|
|
124
|
+
dependency.logger?.info(`Recording proxy started on port ${port}. Press Ctrl+C to stop.`);
|
|
132
125
|
// Wait for Ctrl+C signal
|
|
133
126
|
return new Promise((resolve) => {
|
|
134
127
|
process.on('SIGINT', () => {
|
|
@@ -142,7 +135,7 @@ function registerProxyCommands(main) {
|
|
|
142
135
|
// Playbackモード
|
|
143
136
|
// eslint-disable-next-line no-constant-condition
|
|
144
137
|
while (true) {
|
|
145
|
-
await withPlaybackProxy(
|
|
138
|
+
await withPlaybackProxy({ inventoryRepository, port }, dependency, async () => {
|
|
146
139
|
const watcher = Watch(inventoryRepository.dirPath, { recursive: true });
|
|
147
140
|
return new Promise((ok) => {
|
|
148
141
|
watcher.on('change', () => {
|
|
@@ -160,4 +153,4 @@ registerLighthouseCommands(main);
|
|
|
160
153
|
registerLoadshowCommands(main);
|
|
161
154
|
registerProxyCommands(main);
|
|
162
155
|
main.parse(process.argv);
|
|
163
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
156
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbWFuZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb21tYW5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ25DLE9BQU8sS0FBSyxNQUFNLFlBQVksQ0FBQTtBQUU5QixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDNUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFHNUMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLGtCQUFrQixFQUFFLE1BQU0sWUFBWSxDQUFBO0FBRXZGLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUE7QUFFbkMsTUFBTSxJQUFJLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQTtBQUMxQixJQUFJLENBQUMsTUFBTSxDQUFDLHVCQUF1QixFQUFFLHFCQUFxQixFQUFFLGFBQWEsQ0FBQyxDQUFBO0FBRTFFLFNBQVMsMEJBQTBCLENBQUMsSUFBYTtJQUMvQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQzdDLFVBQVUsQ0FBQyxXQUFXLENBQUMsbURBQW1ELENBQUMsQ0FBQTtJQUMzRSxVQUFVLENBQUMsTUFBTSxDQUFDLHVCQUF1QixFQUFFLHFCQUFxQixFQUFFLGFBQWEsQ0FBQyxDQUFBO0lBQ2hGLFVBQVUsQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLGNBQWMsRUFBRSxLQUFLLENBQUMsQ0FBQTtJQUN2RCxVQUFVLENBQUMsTUFBTSxDQUFDLG9CQUFvQixFQUFFLHNCQUFzQixFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBRXhFLE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUE7SUFDakQsU0FB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
|
package/build/index.d.ts
CHANGED
|
@@ -4,9 +4,8 @@ export * from './formatting.js';
|
|
|
4
4
|
export * from './http.js';
|
|
5
5
|
export * from './inventory.js';
|
|
6
6
|
export * from './playback.js';
|
|
7
|
-
export * from './proxy.js';
|
|
8
7
|
export * from './recording.js';
|
|
9
|
-
export * from './throttling.js';
|
|
10
8
|
export * from './types.js';
|
|
11
9
|
export * from './lighthouse.js';
|
|
10
|
+
export * from './lighthouse-digest.js';
|
|
12
11
|
export * from './loadshow.js';
|
package/build/index.js
CHANGED
|
@@ -4,10 +4,9 @@ export * from './formatting.js';
|
|
|
4
4
|
export * from './http.js';
|
|
5
5
|
export * from './inventory.js';
|
|
6
6
|
export * from './playback.js';
|
|
7
|
-
export * from './proxy.js';
|
|
8
7
|
export * from './recording.js';
|
|
9
|
-
export * from './throttling.js';
|
|
10
8
|
export * from './types.js';
|
|
11
9
|
export * from './lighthouse.js';
|
|
10
|
+
export * from './lighthouse-digest.js';
|
|
12
11
|
export * from './loadshow.js';
|
|
13
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQkFBaUIsQ0FBQTtBQUMvQixjQUFjLGVBQWUsQ0FBQTtBQUM3QixjQUFjLGlCQUFpQixDQUFBO0FBQy9CLGNBQWMsV0FBVyxDQUFBO0FBQ3pCLGNBQWMsZ0JBQWdCLENBQUE7QUFDOUIsY0FBYyxlQUFlLENBQUE7QUFDN0IsY0FBYyxnQkFBZ0IsQ0FBQTtBQUM5QixjQUFjLFlBQVksQ0FBQTtBQUMxQixjQUFjLGlCQUFpQixDQUFBO0FBQy9CLGNBQWMsd0JBQXdCLENBQUE7QUFDdEMsY0FBYyxlQUFlLENBQUEifQ==
|
package/build/inventory.js
CHANGED
|
@@ -6,6 +6,7 @@ import { convertEditableText, isText } from './formatting.js';
|
|
|
6
6
|
import { parseContentTypeHeader, requestContentFilePath, stringifyContentTypeHeader } from './http.js';
|
|
7
7
|
const InventoryDir = 'inventory';
|
|
8
8
|
const IndexFile = 'index.json';
|
|
9
|
+
const InventoryFile = 'inventory.json'; // Rust proxy uses this name
|
|
9
10
|
export class InventoryRepository {
|
|
10
11
|
dirPath;
|
|
11
12
|
dependency;
|
|
@@ -16,12 +17,25 @@ export class InventoryRepository {
|
|
|
16
17
|
async saveInventory(inventory) {
|
|
17
18
|
const inventoryJson = JSON.stringify(inventory, null, 2);
|
|
18
19
|
await Fsp.mkdir(this.dirPath, { recursive: true });
|
|
20
|
+
// Save as both index.json (legacy) and inventory.json (Rust proxy)
|
|
19
21
|
await Fsp.writeFile(Path.join(this.dirPath, IndexFile), inventoryJson);
|
|
22
|
+
await Fsp.writeFile(Path.join(this.dirPath, InventoryFile), inventoryJson);
|
|
20
23
|
}
|
|
21
24
|
async loadInventory() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
// Try inventory.json first (Rust proxy), fallback to index.json (legacy)
|
|
26
|
+
let inventoryPath = Path.join(this.dirPath, InventoryFile);
|
|
27
|
+
try {
|
|
28
|
+
const inventoryJson = await Fsp.readFile(inventoryPath, 'utf8');
|
|
29
|
+
const inventory = JSON.parse(inventoryJson);
|
|
30
|
+
return inventory;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Fallback to index.json
|
|
34
|
+
inventoryPath = Path.join(this.dirPath, IndexFile);
|
|
35
|
+
const inventoryJson = await Fsp.readFile(inventoryPath, 'utf8');
|
|
36
|
+
const inventory = JSON.parse(inventoryJson);
|
|
37
|
+
return inventory;
|
|
38
|
+
}
|
|
25
39
|
}
|
|
26
40
|
async saveTransactions(transactions) {
|
|
27
41
|
// To keep transactions order in Promise.all,
|
|
@@ -172,4 +186,4 @@ export class InventoryRepository {
|
|
|
172
186
|
return transactions;
|
|
173
187
|
}
|
|
174
188
|
}
|
|
175
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
189
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52ZW50b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ludmVudG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUE7QUFDbkIsT0FBTyxHQUFHLE1BQU0sYUFBYSxDQUFBO0FBQzdCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUV2QixPQUFPLEVBQUUsUUFBUSxFQUF1QixVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDekUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQzdELE9BQU8sRUFBZSxzQkFBc0IsRUFBRSxzQkFBc0IsRUFBRSwwQkFBMEIsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUduSCxNQUFNLFlBQVksR0FBRyxXQUFXLENBQUE7QUFDaEMsTUFBTSxTQUFTLEdBQUcsWUFBWSxDQUFBO0FBQzlCLE1BQU0sYUFBYSxHQUFHLGdCQUFnQixDQUFBLENBQUMsNEJBQTRCO0FBc0NuRSxNQUFNLE9BQU8sbUJBQW1CO0lBQzlCLE9BQU8sQ0FBUztJQUNoQixVQUFVLENBQStCO0lBRXpDLFlBQVksT0FBZ0IsRUFBRSxVQUEwQztRQUN0RSxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQTtRQUNoRSxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsSUFBSSxFQUFFLENBQUE7SUFDcEMsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQUMsU0FBb0I7UUFDdEMsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFBO1FBQ3hELE1BQU0sR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFB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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DependencyInterface } from './types.js';
|
|
2
|
+
export interface CaptureLighthouseDigestInput {
|
|
3
|
+
htmlPath: string;
|
|
4
|
+
outputPath: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Captures a digest screenshot of the Lighthouse report.
|
|
8
|
+
* This function captures two specific sections:
|
|
9
|
+
* 1. The final screenshot header (lh-category-header__finalscreenshot)
|
|
10
|
+
* 2. The metrics audit group (lh-audit-group--metrics)
|
|
11
|
+
*/
|
|
12
|
+
export declare function captureLighthouseDigest(opts: CaptureLighthouseDigestInput, dependency: Pick<DependencyInterface, 'logger' | 'mkdirp'>): Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import Path from 'path';
|
|
2
|
+
import puppeteer from 'puppeteer';
|
|
3
|
+
/**
|
|
4
|
+
* Captures a digest screenshot of the Lighthouse report.
|
|
5
|
+
* This function captures two specific sections:
|
|
6
|
+
* 1. The final screenshot header (lh-category-header__finalscreenshot)
|
|
7
|
+
* 2. The metrics audit group (lh-audit-group--metrics)
|
|
8
|
+
*/
|
|
9
|
+
export async function captureLighthouseDigest(opts, dependency) {
|
|
10
|
+
const browser = await puppeteer.launch({
|
|
11
|
+
headless: true,
|
|
12
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
13
|
+
});
|
|
14
|
+
try {
|
|
15
|
+
const page = await browser.newPage();
|
|
16
|
+
// Load the HTML file
|
|
17
|
+
const fileUrl = `file://${Path.resolve(opts.htmlPath)}`;
|
|
18
|
+
await page.goto(fileUrl, { waitUntil: 'networkidle0' });
|
|
19
|
+
// Check if the required elements exist
|
|
20
|
+
const elementsExist = await page.evaluate(() => {
|
|
21
|
+
const finalScreenshot = document.querySelector('.lh-category-header__finalscreenshot');
|
|
22
|
+
const metrics = document.querySelector('.lh-audit-group--metrics');
|
|
23
|
+
return finalScreenshot !== null && metrics !== null;
|
|
24
|
+
});
|
|
25
|
+
if (!elementsExist) {
|
|
26
|
+
throw new Error('Required elements not found in the Lighthouse report');
|
|
27
|
+
}
|
|
28
|
+
// Get the bounding boxes of both elements
|
|
29
|
+
const finalScreenshotElement = await page.$('.lh-category-header__finalscreenshot');
|
|
30
|
+
const metricsElement = await page.$('.lh-audit-group--metrics');
|
|
31
|
+
if (!finalScreenshotElement || !metricsElement) {
|
|
32
|
+
throw new Error('Required elements not found in the Lighthouse report');
|
|
33
|
+
}
|
|
34
|
+
const finalScreenshotBox = await finalScreenshotElement.boundingBox();
|
|
35
|
+
const metricsBox = await metricsElement.boundingBox();
|
|
36
|
+
if (!finalScreenshotBox || !metricsBox) {
|
|
37
|
+
throw new Error('Could not get bounding box of required elements');
|
|
38
|
+
}
|
|
39
|
+
// Calculate the bounding box that encompasses both elements
|
|
40
|
+
const minX = Math.min(finalScreenshotBox.x, metricsBox.x);
|
|
41
|
+
const minY = Math.min(finalScreenshotBox.y, metricsBox.y);
|
|
42
|
+
const maxX = Math.max(finalScreenshotBox.x + finalScreenshotBox.width, metricsBox.x + metricsBox.width);
|
|
43
|
+
const maxY = Math.max(finalScreenshotBox.y + finalScreenshotBox.height, metricsBox.y + metricsBox.height);
|
|
44
|
+
const boundingBox = {
|
|
45
|
+
x: minX,
|
|
46
|
+
y: minY,
|
|
47
|
+
width: maxX - minX,
|
|
48
|
+
height: maxY - minY,
|
|
49
|
+
};
|
|
50
|
+
// Ensure output directory exists
|
|
51
|
+
const outputDir = Path.dirname(opts.outputPath);
|
|
52
|
+
await dependency.mkdirp(outputDir);
|
|
53
|
+
// Capture the screenshot
|
|
54
|
+
await page.screenshot({
|
|
55
|
+
path: opts.outputPath,
|
|
56
|
+
clip: {
|
|
57
|
+
x: boundingBox.x,
|
|
58
|
+
y: boundingBox.y,
|
|
59
|
+
width: boundingBox.width,
|
|
60
|
+
height: boundingBox.height,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
dependency.logger?.info(`Lighthouse digest screenshot saved to ${opts.outputPath}`);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
await browser.close();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlnaHRob3VzZS1kaWdlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbGlnaHRob3VzZS1kaWdlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRXZCLE9BQU8sU0FBUyxNQUFNLFdBQVcsQ0FBQTtBQVNqQzs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsdUJBQXVCLENBQzNDLElBQWtDLEVBQ2xDLFVBQTBEO0lBRTFELE1BQU0sT0FBTyxHQUFHLE1BQU0sU0FBUyxDQUFDLE1BQU0sQ0FBQztRQUNyQyxRQUFRLEVBQUUsSUFBSTtRQUNkLElBQUksRUFBRSxDQUFDLGNBQWMsRUFBRSwwQkFBMEIsQ0FBQztLQUNuRCxDQUFDLENBQUE7SUFFRixJQUFJO1FBQ0YsTUFBTSxJQUFJLEdBQUcsTUFBTSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUE7UUFFcEMscUJBQXFCO1FBQ3JCLE1BQU0sT0FBTyxHQUFHLFVBQVUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQTtRQUN2RCxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQUE7UUFFdkQsdUNBQXVDO1FBQ3ZDLE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEVBQUU7WUFDN0MsTUFBTSxlQUFlLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFBO1lBQ3RGLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsMEJBQTBCLENBQUMsQ0FBQTtZQUNsRSxPQUFPLGVBQWUsS0FBSyxJQUFJLElBQUksT0FBTyxLQUFLLElBQUksQ0FBQTtRQUNyRCxDQUFDLENBQUMsQ0FBQTtRQUVGLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDbEIsTUFBTSxJ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
|
package/build/lighthouse.d.ts
CHANGED
|
@@ -3,11 +3,10 @@ export interface ExecLighthouseInput {
|
|
|
3
3
|
url: string;
|
|
4
4
|
proxyPort: number;
|
|
5
5
|
deviceType?: DeviceType;
|
|
6
|
-
cpuMultiplier?: string;
|
|
7
|
-
noThrottling?: boolean;
|
|
8
6
|
view?: boolean;
|
|
9
7
|
artifactsDir?: string;
|
|
10
8
|
headless: boolean;
|
|
11
9
|
timeout: number;
|
|
10
|
+
captureScoreAndMetrics?: boolean;
|
|
12
11
|
}
|
|
13
|
-
export declare function execLighthouse(opts: ExecLighthouseInput, dependency: Pick<DependencyInterface, 'mkdirp' | 'executeLighthouse'>): Promise<void>;
|
|
12
|
+
export declare function execLighthouse(opts: ExecLighthouseInput, dependency: Pick<DependencyInterface, 'mkdirp' | 'executeLighthouse' | 'logger'>): Promise<void>;
|
package/build/lighthouse.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Path from 'path';
|
|
2
|
+
import { captureLighthouseDigest } from './lighthouse-digest.js';
|
|
2
3
|
export async function execLighthouse(opts, dependency) {
|
|
3
4
|
const artifactsDir = opts.artifactsDir || './artifacts';
|
|
4
5
|
await dependency.mkdirp(artifactsDir);
|
|
@@ -11,12 +12,15 @@ export async function execLighthouse(opts, dependency) {
|
|
|
11
12
|
`--output-path=${outputPath}`,
|
|
12
13
|
'--only-categories=performance',
|
|
13
14
|
`--form-factor=${deviceType}`,
|
|
15
|
+
// Set screen emulation to match form factor
|
|
16
|
+
`--screenEmulation.mobile=${deviceType === 'mobile' ? 'true' : 'false'}`,
|
|
17
|
+
// Disable throttling as Rust proxy handles timing accurately
|
|
18
|
+
'--throttling.rttMs=0',
|
|
19
|
+
'--throttling.throughputKbps=0',
|
|
20
|
+
'--throttling.downloadThroughputKbps=0',
|
|
21
|
+
'--throttling.uploadThroughputKbps=0',
|
|
22
|
+
'--throttling.cpuSlowdownMultiplier=1',
|
|
14
23
|
];
|
|
15
|
-
if (opts.noThrottling) {
|
|
16
|
-
args.push('--throttling.rttMs=0', '--throttling.throughputKbps=0', '--throttling.downloadThroughputKbps=0', '--throttling.uploadThroughputKbps=0', '--throttling.cpuSlowdownMultiplier=1');
|
|
17
|
-
}
|
|
18
|
-
else if (opts.cpuMultiplier)
|
|
19
|
-
args.push(`--throttling.cpuSlowdownMultiplier=${opts.cpuMultiplier}`);
|
|
20
24
|
args.push(`--max-wait-for-load=${opts.timeout}`);
|
|
21
25
|
const chromeFlags = ['--ignore-certificate-errors', `--proxy-server=http://localhost:${opts.proxyPort}`];
|
|
22
26
|
if (opts.headless)
|
|
@@ -25,5 +29,19 @@ export async function execLighthouse(opts, dependency) {
|
|
|
25
29
|
if (opts.view)
|
|
26
30
|
args.push('--view');
|
|
27
31
|
await dependency.executeLighthouse(args);
|
|
32
|
+
// Capture score and metrics screenshot if requested
|
|
33
|
+
if (opts.captureScoreAndMetrics !== false) {
|
|
34
|
+
const htmlPath = `${outputPath}.report.html`;
|
|
35
|
+
const digestPath = Path.join(artifactsDir, 'lighthouse.digest.png');
|
|
36
|
+
try {
|
|
37
|
+
await captureLighthouseDigest({
|
|
38
|
+
htmlPath,
|
|
39
|
+
outputPath: digestPath,
|
|
40
|
+
}, dependency);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
dependency.logger?.warn(`Failed to capture Lighthouse score and metrics: ${error}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
28
46
|
}
|
|
29
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlnaHRob3VzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9saWdodGhvdXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUV2QixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQTtBQWNoRSxNQUFNLENBQUMsS0FBSyxVQUFVLGNBQWMsQ0FDbEMsSUFBeUIsRUFDekIsVUFBZ0Y7SUFFaEYsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFlBQVksSUFBSSxhQUFhLENBQUE7SUFDdkQsTUFBTSxVQUFVLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBRXJDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLElBQUksUUFBUSxDQUFBO0lBQzlDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFBO0lBQ3hELE1BQU0sSUFBSSxHQUFhO1FBQ3JCLElBQUksQ0FBQyxHQUFHO1FBQ1IsZUFBZTtRQUNmLG9CQUFvQjtRQUNwQixpQkFBaUIsVUFBVSxFQUFFO1FBQzdCLCtCQUErQjtRQUMvQixpQkFBaUIsVUFBVSxFQUFFO1FBQzdCLDRDQUE0QztRQUM1Qyw0QkFBNEIsVUFBVSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUU7UUFDeEUsNkRBQTZEO1FBQzdELHNCQUFzQjtRQUN0QiwrQkFBK0I7UUFDL0IsdUNBQXVDO1FBQ3ZDLHFDQUFxQztRQUNyQyxzQ0FBc0M7S0FDdkMsQ0FBQTtJQUVELElBQUksQ0FBQyxJQUFJLENBQUMsdUJBQXVCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFBO0lBRWhELE1BQU0sV0FBVyxHQUFhLENBQUMsNkJBQTZCLEVBQUUsbUNBQW1DLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFBO0lBQ2xILElBQUksSUFBSSxDQUFDLFFBQVE7UUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ2pELElBQUksQ0FBQyxJQUFJLENBQUMsbUJBQW1CLFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBRXRELElBQUksSUFBSSxDQUFDLElBQUk7UUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBRWxDLE1BQU0sVUFBVSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFBO0lBRXhDLG9EQUFvRDtJQUNwRCxJQUFJLElBQUksQ0FBQyxzQkFBc0IsS0FBSyxLQUFLLEVBQUU7UUFDekMsTUFBTSxRQUFRLEdBQUcsR0FBRyxVQUFVLGNBQWMsQ0FBQTtRQUM1QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSx1QkFBdUIsQ0FBQyxDQUFBO1FBRW5FLElBQUk7WUFDRixNQUFNLHVCQUF1QixDQUMzQjtnQkFDRSxRQUFRO2dCQUNSLFVBQVUsRUFBRSxVQUFVO2FBQ3ZCLEVBQ0QsVUFBVSxDQUNYLENBQUE7U0FDRjtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ2QsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsbURBQW1ELEtBQUssRUFBRSxDQUFDLENBQUE7U0FDcEY7S0FDRjtBQUNILENBQUMifQ==
|
package/build/loadshow.d.ts
CHANGED
|
@@ -3,8 +3,6 @@ export interface ExecLoadshowInput {
|
|
|
3
3
|
url: string;
|
|
4
4
|
proxyPort: number;
|
|
5
5
|
deviceType?: DeviceType;
|
|
6
|
-
noThrottling?: boolean;
|
|
7
|
-
syncLighthouseSpec?: boolean;
|
|
8
6
|
artifactsDir?: string;
|
|
9
7
|
timeout: number;
|
|
10
8
|
credit?: string;
|
|
@@ -13,8 +11,6 @@ export interface ExecLoadshowSpec {
|
|
|
13
11
|
viewportWidth?: number;
|
|
14
12
|
columns?: number;
|
|
15
13
|
cpuThrottling?: number;
|
|
16
|
-
networkLatencyMs?: number;
|
|
17
|
-
networkThroughputMbps?: number;
|
|
18
14
|
timeoutMs?: number;
|
|
19
15
|
userAgent?: string;
|
|
20
16
|
proxyPort?: number;
|
package/build/loadshow.js
CHANGED
|
@@ -10,12 +10,6 @@ function execSpecToCommandArgs(spec) {
|
|
|
10
10
|
args.push('-u', `recording.viewportWidth=${spec.viewportWidth}`);
|
|
11
11
|
if (spec.cpuThrottling !== undefined)
|
|
12
12
|
args.push('-u', `recording.cpuThrottling=${spec.cpuThrottling}`);
|
|
13
|
-
if (spec.networkLatencyMs !== undefined)
|
|
14
|
-
args.push('-u', `recording.network.latencyMs=${spec.networkLatencyMs}`);
|
|
15
|
-
if (spec.networkThroughputMbps !== undefined) {
|
|
16
|
-
args.push('-u', `recording.network.uploadThroughputMbps=${spec.networkThroughputMbps}`);
|
|
17
|
-
args.push('-u', `recording.network.downloadThroughputMbps=${spec.networkThroughputMbps}`);
|
|
18
|
-
}
|
|
19
13
|
if (spec.timeoutMs !== undefined)
|
|
20
14
|
args.push('-u', `recording.timeoutMs=${spec.timeoutMs}`);
|
|
21
15
|
if (spec.userAgent !== undefined)
|
|
@@ -48,21 +42,8 @@ export async function execLoadshow(input, dependency) {
|
|
|
48
42
|
cpuThrottling: lighthouseByDevice.settings?.throttling?.cpuSlowdownMultiplier,
|
|
49
43
|
userAgent: typeof userAgent === 'string' ? userAgent : undefined,
|
|
50
44
|
timeoutMs: input.timeout,
|
|
45
|
+
credit: input.credit,
|
|
51
46
|
};
|
|
52
|
-
// Sync network conditions with Lighthouse
|
|
53
|
-
if (input.syncLighthouseSpec) {
|
|
54
|
-
if (lighthouseByDevice.settings?.throttling?.rttMs)
|
|
55
|
-
spec.networkLatencyMs = lighthouseByDevice.settings?.throttling?.rttMs;
|
|
56
|
-
if (lighthouseByDevice.settings?.throttling?.throughputKbps)
|
|
57
|
-
spec.networkThroughputMbps = lighthouseByDevice.settings?.throttling?.throughputKbps / 1024;
|
|
58
|
-
}
|
|
59
|
-
// No throttling
|
|
60
|
-
if (input.noThrottling) {
|
|
61
|
-
spec.networkLatencyMs = 0;
|
|
62
|
-
spec.networkThroughputMbps = 999999;
|
|
63
|
-
}
|
|
64
|
-
// Credit
|
|
65
|
-
spec.credit = input.credit;
|
|
66
47
|
const args = [];
|
|
67
48
|
args.push('record');
|
|
68
49
|
args.push('-a', loadshowDir);
|
|
@@ -70,4 +51,4 @@ export async function execLoadshow(input, dependency) {
|
|
|
70
51
|
args.push(input.url, outputPath);
|
|
71
52
|
await dependency.executeLoadshow(args);
|
|
72
53
|
}
|
|
73
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
54
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZHNob3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbG9hZHNob3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRXZCLE9BQU8sRUFBRSxhQUFhLEVBQUUsYUFBYSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBdUJ6RCxTQUFTLHFCQUFxQixDQUFDLElBQXNCO0lBQ25ELE1BQU0sSUFBSSxHQUFhLEVBQUUsQ0FBQTtJQUV6QixTQUFTO0lBQ1QsSUFBSSxJQUFJLENBQUMsT0FBTyxLQUFLLFNBQVM7UUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxrQkFBa0IsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUE7SUFFakYsWUFBWTtJQUNaLElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSyxTQUFTO1FBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsMkJBQTJCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFBO0lBQ3RHLElBQUksSUFBSSxDQUFDLGFBQWEsS0FBSyxTQUFTO1FBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsMkJBQTJCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFBO0lBQ3RHLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTO1FBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFBO0lBQzFGLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTO1FBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsZ0NBQWdDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFBO0lBRW5HLHNCQUFzQjtJQUN0QixNQUFNLFVBQVUsR0FBYSxDQUFDLDZCQUE2QixDQUFDLENBQUE7SUFDNUQsSUFBSSxJQUFJLENBQUMsU0FBUyxLQUFLLFNBQVMs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
|
package/build/playback.d.ts
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
url: string;
|
|
8
|
-
ttfbMs: number;
|
|
9
|
-
statusCode?: number;
|
|
10
|
-
err?: Error;
|
|
11
|
-
rawHeaders?: HttpHeaders;
|
|
12
|
-
contentChunks: Buffer[];
|
|
13
|
-
contentLength: number;
|
|
14
|
-
durationMs: number;
|
|
1
|
+
import { Proxy as RustProxy } from 'rust-http-playback-proxy';
|
|
2
|
+
import { InventoryRepository } from './inventory.js';
|
|
3
|
+
import { DependencyInterface, DeviceType } from './types.js';
|
|
4
|
+
export interface PlaybackProxyOptions {
|
|
5
|
+
inventoryRepository?: InventoryRepository;
|
|
6
|
+
port?: number;
|
|
15
7
|
}
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
export type PlaybackProxyDependency = Pick<DependencyInterface, 'logger'>;
|
|
9
|
+
export declare class PlaybackProxy {
|
|
10
|
+
rustProxy?: RustProxy;
|
|
11
|
+
inventoryRepository: InventoryRepository;
|
|
12
|
+
entryUrl?: string;
|
|
13
|
+
deviceType?: DeviceType;
|
|
14
|
+
requestedPort?: number;
|
|
15
|
+
dependency: PlaybackProxyDependency;
|
|
16
|
+
constructor(options?: PlaybackProxyOptions, dependency?: PlaybackProxyDependency);
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
get port(): number;
|
|
19
|
+
get inventoryDirPath(): string;
|
|
20
|
+
stop(): Promise<void>;
|
|
22
21
|
}
|
|
23
|
-
export declare function withPlaybackProxy(options:
|
|
22
|
+
export declare function withPlaybackProxy(options: PlaybackProxyOptions, dependency: PlaybackProxyDependency, cb: (proxy: PlaybackProxy) => Promise<void>): Promise<void>;
|
package/build/playback.js
CHANGED
|
@@ -1,110 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export class PlaybackProxy
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
contentLength: 0,
|
|
18
|
-
durationMs: transaction.durationMs || 0,
|
|
19
|
-
};
|
|
20
|
-
if (transaction.content) {
|
|
21
|
-
const maxChunks = 10;
|
|
22
|
-
const minInterval = 10;
|
|
23
|
-
const chunks = Math.min(maxChunks, Math.floor(playbackTransaction.durationMs / minInterval));
|
|
24
|
-
playbackTransaction.contentChunks = [];
|
|
25
|
-
const chunkSize = Math.max(ChunkSize, Math.ceil(transaction.content.length / chunks));
|
|
26
|
-
for (let i = 0; i <= transaction.content.length; i += chunkSize) {
|
|
27
|
-
playbackTransaction.contentChunks.push(transaction.content.subarray(i, i + chunkSize));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (!this.transactionsMap.has(transaction.method)) {
|
|
31
|
-
this.transactionsMap.set(transaction.method, new Map());
|
|
32
|
-
}
|
|
33
|
-
this.transactionsMap.get(transaction.method).set(transaction.url, playbackTransaction);
|
|
34
|
-
}
|
|
1
|
+
import { startPlayback } from 'rust-http-playback-proxy';
|
|
2
|
+
import { InventoryRepository } from './inventory.js';
|
|
3
|
+
export class PlaybackProxy {
|
|
4
|
+
rustProxy;
|
|
5
|
+
inventoryRepository;
|
|
6
|
+
entryUrl;
|
|
7
|
+
deviceType;
|
|
8
|
+
requestedPort;
|
|
9
|
+
dependency;
|
|
10
|
+
constructor(options, dependency) {
|
|
11
|
+
options ||= {};
|
|
12
|
+
this.dependency = dependency || {};
|
|
13
|
+
// Inventory repository
|
|
14
|
+
this.inventoryRepository = options.inventoryRepository ?? new InventoryRepository(undefined, this.dependency);
|
|
15
|
+
// Port
|
|
16
|
+
this.requestedPort = options.port;
|
|
35
17
|
}
|
|
36
|
-
async
|
|
18
|
+
async start() {
|
|
19
|
+
this.dependency.logger?.info(`Starting playback proxy...`);
|
|
20
|
+
// Load inventory to get entryUrl and deviceType
|
|
37
21
|
const inventory = await this.inventoryRepository.loadInventory();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const number = requestNumber++;
|
|
44
|
-
// Skip websocket
|
|
45
|
-
if (ctx.clientToProxyRequest.headers?.upgrade === 'websocket') {
|
|
46
|
-
this.dependency.logger?.warn({ number }, `Request #${number} ${ctx.clientToProxyRequest.url} skipped (websocket)`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const identifier = Proxy.contextRequest(ctx);
|
|
50
|
-
const transaction = this.transactionsMap.get(identifier.method)?.get(identifier.url);
|
|
51
|
-
if (!transaction) {
|
|
52
|
-
this.dependency.logger?.warn({ number, identifier }, `Request #${number} ${identifier.url} (${identifier.method}) not found in inventory`);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
const contentStream = this.createThrottlingTransform() || ctx.proxyToClientResponse;
|
|
56
|
-
if (contentStream !== ctx.proxyToClientResponse) {
|
|
57
|
-
contentStream.pipe(ctx.proxyToClientResponse);
|
|
58
|
-
}
|
|
59
|
-
this.dependency.logger?.debug({ number, identifier }, `Request #${number} ${transaction.url} started`);
|
|
60
|
-
ctx.onError((_, err) => {
|
|
61
|
-
this.dependency.logger?.warn({ number, identifier, err }, `Request #${number} ${transaction.url} failed: ${err.message}`);
|
|
62
|
-
});
|
|
63
|
-
setTimeout(() => {
|
|
64
|
-
// Error
|
|
65
|
-
if (transaction.err) {
|
|
66
|
-
return onRequestComplete(transaction.err);
|
|
67
|
-
}
|
|
68
|
-
// Status code
|
|
69
|
-
ctx.proxyToClientResponse.statusCode = transaction.statusCode || 500;
|
|
70
|
-
// Headers
|
|
71
|
-
if (transaction.rawHeaders) {
|
|
72
|
-
for (const [key, value] of Object.entries(transaction.rawHeaders)) {
|
|
73
|
-
if (ctx.proxyToClientResponse.headersSent)
|
|
74
|
-
break;
|
|
75
|
-
ctx.proxyToClientResponse.setHeader(key, value);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// Empty content body
|
|
79
|
-
if (!transaction.contentChunks || transaction.contentChunks.length === 0) {
|
|
80
|
-
contentStream.end();
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
// Content body
|
|
84
|
-
const chunks = [...transaction.contentChunks];
|
|
85
|
-
const intervalMs = transaction.durationMs / transaction.contentChunks.length;
|
|
86
|
-
const interval = setInterval(() => {
|
|
87
|
-
const chunk = chunks.shift();
|
|
88
|
-
if (chunk) {
|
|
89
|
-
contentStream.write(chunk);
|
|
90
|
-
}
|
|
91
|
-
if (chunks.length === 0) {
|
|
92
|
-
clearInterval(interval);
|
|
93
|
-
contentStream.end();
|
|
94
|
-
this.dependency.logger?.debug({ number, identifier }, `Request #${number} ${transaction.url} completed`);
|
|
95
|
-
}
|
|
96
|
-
}, intervalMs);
|
|
97
|
-
}, transaction.ttfbMs);
|
|
22
|
+
this.entryUrl = inventory.entryUrl;
|
|
23
|
+
this.deviceType = inventory.deviceType;
|
|
24
|
+
this.rustProxy = await startPlayback({
|
|
25
|
+
inventoryDir: this.inventoryRepository.dirPath,
|
|
26
|
+
port: this.requestedPort || 0,
|
|
98
27
|
});
|
|
28
|
+
this.dependency.logger?.info(`Playback proxy started on port ${this.rustProxy.port}`);
|
|
29
|
+
}
|
|
30
|
+
get port() {
|
|
31
|
+
if (!this.rustProxy)
|
|
32
|
+
throw new Error('Proxy not started');
|
|
33
|
+
return this.rustProxy.port;
|
|
34
|
+
}
|
|
35
|
+
get inventoryDirPath() {
|
|
36
|
+
return this.inventoryRepository.dirPath;
|
|
99
37
|
}
|
|
100
|
-
async
|
|
101
|
-
|
|
38
|
+
async stop() {
|
|
39
|
+
if (this.rustProxy) {
|
|
40
|
+
this.dependency.logger?.info(`Stopping playback proxy...`);
|
|
41
|
+
await this.rustProxy.stop();
|
|
42
|
+
this.dependency.logger?.info(`Playback proxy stopped`);
|
|
43
|
+
}
|
|
102
44
|
}
|
|
103
45
|
}
|
|
104
46
|
export async function withPlaybackProxy(options, dependency, cb) {
|
|
105
47
|
const proxy = new PlaybackProxy(options, dependency);
|
|
106
48
|
await proxy.start();
|
|
107
|
-
|
|
108
|
-
|
|
49
|
+
try {
|
|
50
|
+
await cb(proxy);
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await proxy.stop();
|
|
54
|
+
}
|
|
109
55
|
}
|
|
110
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxheWJhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcGxheWJhY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFzQixhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQTtBQUU1RSxPQUFPLEVBQWEsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQVUvRCxNQUFNLE9BQU8sYUFBYTtJQUN4QixTQUFTLENBQVk7SUFDckIsbUJBQW1CLENBQXNCO0lBQ3pDLFFBQVEsQ0FBUztJQUNqQixVQUFVLENBQWE7SUFDdkIsYUFBYSxDQUFTO0lBQ3RCLFVBQVUsQ0FBeUI7SUFFbkMsWUFBWSxPQUE4QixFQUFFLFVBQW9DO1FBQzlFLE9BQU8sS0FBSyxFQUFFLENBQUE7UUFDZCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsSUFBSSxFQUFFLENBQUE7UUFFbEMsdUJBQXVCO1FBQ3ZCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxPQUFPLENBQUMsbUJBQW1CLElBQUksSUFBSSxtQkFBbUIsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBRTdHLE9BQU87UUFDUCxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUE7SUFDbkMsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLDRCQUE0QixDQUFDLENBQUE7UUFFMUQsZ0RBQWdEO1FBQ2hELE1BQU0sU0FBUyxHQUFjLE1BQU0sSUFBSSxDQUFDLG1CQUFtQixDQUFDLGFBQWEsRUFBRSxDQUFBO1FBQzNFLElBQUksQ0FBQyxRQUFRLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQTtRQUNsQyxJQUFJLENBQUMsVUFBVSxHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUE7UUFFdEMsSUFBSSxDQUFDLFNBQVMsR0FBRyxNQUFNLGFBQWEsQ0FBQztZQUNuQyxZQUFZLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU87WUFDOUMsSUFBSSxFQUFFLElBQUksQ0FBQyxhQUFhLElBQUksQ0FBQztTQUM5QixDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsa0NBQWtDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUN2RixDQUFDO0lBRUQsSUFBSSxJQUFJO1FBQ04sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFBO1FBQ3pELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUE7SUFDNUIsQ0FBQztJQUVELElBQUksZ0JBQWdCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQTtJQUN6QyxDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUk7UUFDUixJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDbEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLDRCQUE0QixDQUFDLENBQUE7WUFDMUQsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFBO1lBQzNCLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxDQUFBO1NBQ3ZEO0lBQ0gsQ0FBQztDQUNGO0FBRUQsTUFBTSxDQUFDLEtBQUssVUFBVSxpQkFBaUIsQ0FDckMsT0FBNkIsRUFDN0IsVUFBbUMsRUFDbkMsRUFBMkM7SUFFM0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxhQUFhLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFBO0lBQ3BELE1BQU0sS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFBO0lBQ25CLElBQUk7UUFDRixNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtLQUNoQjtZQUFTO1FBQ1IsTUFBTSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUE7S0FDbkI7QUFDSCxDQUFDIn0=
|
package/build/recording.d.ts
CHANGED
|
@@ -1,28 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
method: string;
|
|
10
|
-
url: string;
|
|
11
|
-
statusCode?: number;
|
|
12
|
-
incomingHttpHeaders?: IncomingHttpHeaders;
|
|
13
|
-
contentChunks: Buffer[];
|
|
14
|
-
err?: Error;
|
|
15
|
-
errKind?: string;
|
|
1
|
+
import { Proxy as RustProxy } from 'rust-http-playback-proxy';
|
|
2
|
+
import { InventoryRepository } from './inventory.js';
|
|
3
|
+
import { DependencyInterface, DeviceType } from './types.js';
|
|
4
|
+
export interface RecordingProxyOptions {
|
|
5
|
+
inventoryRepository?: InventoryRepository;
|
|
6
|
+
entryUrl?: string;
|
|
7
|
+
deviceType?: DeviceType;
|
|
8
|
+
port?: number;
|
|
16
9
|
}
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
export type RecordingProxyDependency = Pick<DependencyInterface, 'logger'>;
|
|
11
|
+
export declare class RecordingProxy {
|
|
12
|
+
rustProxy?: RustProxy;
|
|
13
|
+
inventoryRepository: InventoryRepository;
|
|
14
|
+
entryUrl?: string;
|
|
15
|
+
deviceType?: DeviceType;
|
|
16
|
+
requestedPort?: number;
|
|
17
|
+
dependency: RecordingProxyDependency;
|
|
18
|
+
constructor(options?: RecordingProxyOptions, dependency?: RecordingProxyDependency);
|
|
19
|
+
start(): Promise<void>;
|
|
20
|
+
get port(): number;
|
|
21
|
+
get inventoryDirPath(): string;
|
|
22
|
+
stop(): Promise<void>;
|
|
20
23
|
}
|
|
21
|
-
export declare
|
|
22
|
-
startedAt?: Date;
|
|
23
|
-
transactions: RecordingTransaction[];
|
|
24
|
-
setup(): Promise<void>;
|
|
25
|
-
saveInventory(): Promise<void>;
|
|
26
|
-
shutdown(): Promise<void>;
|
|
27
|
-
}
|
|
28
|
-
export declare function withRecordingProxy(options: ProxyOptions, dependency: ProxyDependency, cb: (proxy: RecordingProxy) => Promise<void>): Promise<void>;
|
|
24
|
+
export declare function withRecordingProxy(options: RecordingProxyOptions, dependency: RecordingProxyDependency, cb: (proxy: RecordingProxy) => Promise<void>): Promise<void>;
|
package/build/recording.js
CHANGED
|
@@ -1,99 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.dependency.logger?.warn({ number, identifier, err }, `Request #${number} ${transaction.url} failed: ${err.message}`);
|
|
31
|
-
});
|
|
32
|
-
ctx.onResponse((_, onResponseComplete) => {
|
|
33
|
-
transaction.responseStartedAt = new Date();
|
|
34
|
-
transaction.statusCode = ctx.serverToProxyResponse.statusCode;
|
|
35
|
-
transaction.incomingHttpHeaders = ctx.serverToProxyResponse.headers;
|
|
36
|
-
this.dependency.logger?.debug({ number, identifier }, `Request #${number} ${transaction.url} responded`);
|
|
37
|
-
onResponseComplete();
|
|
38
|
-
});
|
|
39
|
-
ctx.onResponseData((_, chunk, onResponseDataComplete) => {
|
|
40
|
-
transaction.contentChunks.push(chunk);
|
|
41
|
-
onResponseDataComplete(null, chunk);
|
|
42
|
-
});
|
|
43
|
-
ctx.onResponseEnd((_, onResponseEndComplete) => {
|
|
44
|
-
transaction.responseEndedAt = new Date();
|
|
45
|
-
this.transactions.push(transaction);
|
|
46
|
-
this.dependency.logger?.debug({ number, identifier }, `Request #${number} ${transaction.url} completed`);
|
|
47
|
-
onResponseEndComplete();
|
|
48
|
-
});
|
|
49
|
-
onRequestComplete();
|
|
1
|
+
import { startRecording } from 'rust-http-playback-proxy';
|
|
2
|
+
import { InventoryRepository } from './inventory.js';
|
|
3
|
+
export class RecordingProxy {
|
|
4
|
+
rustProxy;
|
|
5
|
+
inventoryRepository;
|
|
6
|
+
entryUrl;
|
|
7
|
+
deviceType;
|
|
8
|
+
requestedPort;
|
|
9
|
+
dependency;
|
|
10
|
+
constructor(options, dependency) {
|
|
11
|
+
options ||= {};
|
|
12
|
+
this.dependency = dependency || {};
|
|
13
|
+
// Inventory repository
|
|
14
|
+
this.inventoryRepository = options.inventoryRepository ?? new InventoryRepository(undefined, this.dependency);
|
|
15
|
+
// Entry URL
|
|
16
|
+
this.entryUrl = options.entryUrl;
|
|
17
|
+
// Device type
|
|
18
|
+
this.deviceType = options.deviceType;
|
|
19
|
+
// Port
|
|
20
|
+
this.requestedPort = options.port;
|
|
21
|
+
}
|
|
22
|
+
async start() {
|
|
23
|
+
this.dependency.logger?.info(`Starting recording proxy...`);
|
|
24
|
+
const proxyPort = this.requestedPort || 0;
|
|
25
|
+
this.rustProxy = await startRecording({
|
|
26
|
+
entryUrl: this.entryUrl,
|
|
27
|
+
deviceType: this.deviceType,
|
|
28
|
+
inventoryDir: this.inventoryRepository.dirPath,
|
|
29
|
+
port: proxyPort,
|
|
50
30
|
});
|
|
31
|
+
this.dependency.logger?.info(`Recording proxy started on port ${this.rustProxy.port}`);
|
|
51
32
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
content: Buffer.concat(requestTransaction.contentChunks),
|
|
60
|
-
};
|
|
61
|
-
// ttfb and duration
|
|
62
|
-
if (requestTransaction.responseStartedAt) {
|
|
63
|
-
transaction.ttfbMs = +requestTransaction.responseStartedAt - +requestTransaction.startedAt;
|
|
64
|
-
if (requestTransaction.responseEndedAt) {
|
|
65
|
-
transaction.durationMs = +requestTransaction.responseEndedAt - +requestTransaction.responseStartedAt;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// error
|
|
69
|
-
if (requestTransaction.err) {
|
|
70
|
-
transaction.errorMessage = requestTransaction.err.message;
|
|
71
|
-
}
|
|
72
|
-
// status code
|
|
73
|
-
if (requestTransaction.statusCode) {
|
|
74
|
-
transaction.statusCode = requestTransaction.statusCode;
|
|
75
|
-
}
|
|
76
|
-
// headers
|
|
77
|
-
if (requestTransaction.incomingHttpHeaders) {
|
|
78
|
-
transaction.rawHeaders = {};
|
|
79
|
-
for (const [key, value] of Object.entries(requestTransaction.incomingHttpHeaders)) {
|
|
80
|
-
transaction.rawHeaders[key.toLowerCase()] = value.toString();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
transactions.push(transaction);
|
|
84
|
-
}
|
|
85
|
-
const resources = await this.inventoryRepository.saveTransactions(transactions);
|
|
86
|
-
const inventory = { entryUrl: this.entryUrl, deviceType: this.deviceType, resources };
|
|
87
|
-
await this.inventoryRepository.saveInventory(inventory);
|
|
33
|
+
get port() {
|
|
34
|
+
if (!this.rustProxy)
|
|
35
|
+
throw new Error('Proxy not started');
|
|
36
|
+
return this.rustProxy.port;
|
|
37
|
+
}
|
|
38
|
+
get inventoryDirPath() {
|
|
39
|
+
return this.inventoryRepository.dirPath;
|
|
88
40
|
}
|
|
89
|
-
async
|
|
90
|
-
|
|
41
|
+
async stop() {
|
|
42
|
+
if (this.rustProxy) {
|
|
43
|
+
this.dependency.logger?.info(`Stopping recording proxy...`);
|
|
44
|
+
// Stop the proxy (this triggers graceful shutdown via SIGTERM signal)
|
|
45
|
+
// The Rust proxy will save index.json automatically during graceful shutdown
|
|
46
|
+
await this.rustProxy.stop();
|
|
47
|
+
// Wait for the Rust proxy to finish writing files to disk
|
|
48
|
+
// The Rust proxy needs time to process resources and save index.json
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
50
|
+
this.dependency.logger?.info(`Recording proxy stopped`);
|
|
51
|
+
}
|
|
91
52
|
}
|
|
92
53
|
}
|
|
93
54
|
export async function withRecordingProxy(options, dependency, cb) {
|
|
94
55
|
const proxy = new RecordingProxy(options, dependency);
|
|
95
56
|
await proxy.start();
|
|
96
|
-
|
|
97
|
-
|
|
57
|
+
try {
|
|
58
|
+
await cb(proxy);
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await proxy.stop();
|
|
62
|
+
}
|
|
98
63
|
}
|
|
99
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
64
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JlY29yZGluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQXNCLGNBQWMsRUFBRSxNQUFNLDBCQUEwQixDQUFBO0FBRTdFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBWXBELE1BQU0sT0FBTyxjQUFjO0lBQ3pCLFNBQVMsQ0FBWTtJQUNyQixtQkFBbUIsQ0FBc0I7SUFDekMsUUFBUSxDQUFTO0lBQ2pCLFVBQVUsQ0FBYTtJQUN2QixhQUFhLENBQVM7SUFDdEIsVUFBVSxDQUEwQjtJQUVwQyxZQUFZLE9BQStCLEVBQUUsVUFBcUM7UUFDaEYsT0FBTyxLQUFLLEVBQUUsQ0FBQTtRQUNkLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxJQUFJLEVBQUUsQ0FBQTtRQUVsQyx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDLG1CQUFtQixHQUFHLE9BQU8sQ0FBQyxtQkFBbUIsSUFBSSxJQUFJLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFN0csWUFBWTtRQUNaLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQTtRQUVoQyxjQUFjO1FBQ2QsSUFBSSxDQUFDLFVBQVUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFBO1FBRXBDLE9BQU87UUFDUCxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUE7SUFDbkMsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLDZCQUE2QixDQUFDLENBQUE7UUFFM0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGFBQWEsSUFBSSxDQUFDLENBQUE7UUFFekMsSUFBSSxDQUFDLFNBQVMsR0FBRyxNQUFNLGNBQWMsQ0FBQztZQUNwQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7WUFDdkIsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1lBQzNCLFlBQVksRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsT0FBTztZQUM5QyxJQUFJLEVBQUUsU0FBUztTQUNoQixDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsbUNBQW1DLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtJQUN4RixDQUFDO0lBRUQsSUFBSSxJQUFJO1FBQ04sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFBO1FBQ3pELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUE7SUFDNUIsQ0FBQztJQUVELElBQUksZ0JBQWdCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQTtJQUN6QyxDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUk7UUFDUixJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDbEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLDZCQUE2QixDQUFDLENBQUE7WUFFM0Qsc0VBQXNFO1lBQ3RFLDZFQUE2RTtZQUM3RSxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUE7WUFFM0IsMERBQTBEO1lBQzFELHFFQUFxRTtZQUNyRSxNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUE7WUFFekQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLHlCQUF5QixDQUFDLENBQUE7U0FDeEQ7SUFDSCxDQUFDO0NBQ0Y7QUFFRCxNQUFNLENBQUMsS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxPQUE4QixFQUM5QixVQUFvQyxFQUNwQyxFQUE0QztJQUU1QyxNQUFNLEtBQUssR0FBRyxJQUFJLGNBQWMsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDckQsTUFBTSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUE7SUFDbkIsSUFBSTtRQUNGLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFBO0tBQ2hCO1lBQVM7UUFDUixNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQTtLQUNuQjtBQUNILENBQUMifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pagespeed-quest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A framework for efficient web front-end speed improvement",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -52,19 +52,19 @@
|
|
|
52
52
|
"node": ">=18"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@bitauth/libauth": "^1.17.1",
|
|
56
55
|
"commander": "^11.1.0",
|
|
57
56
|
"execa": "^9.3.1",
|
|
58
|
-
"get-port": "^7.1.0",
|
|
59
|
-
"http-mitm-proxy": "^0.9.0",
|
|
60
57
|
"iconv-lite": "^0.6.3",
|
|
61
58
|
"jschardet": "^3.0.0",
|
|
62
59
|
"lighthouse": "^12.2.1",
|
|
63
|
-
"loadshow": "
|
|
60
|
+
"loadshow": "1.2.0",
|
|
61
|
+
"node-html-to-image": "^5.0.0",
|
|
64
62
|
"node-watch": "^0.7.4",
|
|
65
63
|
"pino": "^9.4.0",
|
|
66
64
|
"pino-pretty": "^11.2.2",
|
|
67
65
|
"prettier": "^2.1.1",
|
|
66
|
+
"puppeteer": "^24.31.0",
|
|
67
|
+
"rust-http-playback-proxy": "0.4.2",
|
|
68
68
|
"tmp-promise": "^3.0.3"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
package/build/proxy.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import HttpMitmProxy from 'http-mitm-proxy';
|
|
2
|
-
import { InventoryRepository } from './inventory.js';
|
|
3
|
-
import { Throttle, ThrottlingTransform } from './throttling.js';
|
|
4
|
-
import { DependencyInterface, DeviceType } from './types.js';
|
|
5
|
-
export interface ProxyOptions extends HttpMitmProxy.IProxyOptions {
|
|
6
|
-
inventoryRepository?: InventoryRepository;
|
|
7
|
-
throttle?: Throttle;
|
|
8
|
-
throttlingRetryIntervalMs?: number;
|
|
9
|
-
entryUrl?: string;
|
|
10
|
-
deviceType?: DeviceType;
|
|
11
|
-
}
|
|
12
|
-
export type ProxyDependency = Pick<DependencyInterface, 'logger'>;
|
|
13
|
-
export declare abstract class Proxy {
|
|
14
|
-
proxyOptions: HttpMitmProxy.IProxyOptions;
|
|
15
|
-
proxy: HttpMitmProxy.IProxy;
|
|
16
|
-
inventoryRepository: InventoryRepository;
|
|
17
|
-
throttle?: Throttle;
|
|
18
|
-
throttlingRetryIntervalMs: number;
|
|
19
|
-
entryUrl?: string;
|
|
20
|
-
deviceType?: DeviceType;
|
|
21
|
-
dependency: ProxyDependency;
|
|
22
|
-
constructor(options?: ProxyOptions, dependency?: ProxyDependency);
|
|
23
|
-
static contextRequest(ctx: HttpMitmProxy.IContext): {
|
|
24
|
-
method: string;
|
|
25
|
-
url: string;
|
|
26
|
-
};
|
|
27
|
-
createThrottlingTransform(): ThrottlingTransform | void;
|
|
28
|
-
abstract setup(): Promise<void>;
|
|
29
|
-
abstract shutdown(): Promise<void>;
|
|
30
|
-
start(): Promise<void>;
|
|
31
|
-
get port(): number;
|
|
32
|
-
get inventoryDirPath(): string;
|
|
33
|
-
stop(): Promise<void>;
|
|
34
|
-
}
|
|
35
|
-
export declare function withProxy<ProxyType extends Proxy>(proxy: ProxyType, fn: (proxy: ProxyType) => Promise<void>): Promise<void>;
|
package/build/proxy.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import Crypto from 'crypto';
|
|
2
|
-
import Fsp from 'fs/promises';
|
|
3
|
-
import Http from 'http';
|
|
4
|
-
import Https from 'https';
|
|
5
|
-
import Os from 'os';
|
|
6
|
-
import Path from 'path';
|
|
7
|
-
import GetPort from 'get-port';
|
|
8
|
-
import HttpMitmProxy from 'http-mitm-proxy';
|
|
9
|
-
import { InventoryRepository } from './inventory.js';
|
|
10
|
-
import { ThrottlingTransform } from './throttling.js';
|
|
11
|
-
export class Proxy {
|
|
12
|
-
proxyOptions;
|
|
13
|
-
proxy;
|
|
14
|
-
inventoryRepository;
|
|
15
|
-
throttle;
|
|
16
|
-
throttlingRetryIntervalMs;
|
|
17
|
-
entryUrl;
|
|
18
|
-
deviceType;
|
|
19
|
-
dependency;
|
|
20
|
-
constructor(options, dependency) {
|
|
21
|
-
options ||= {};
|
|
22
|
-
this.dependency = dependency || {};
|
|
23
|
-
// Proxy
|
|
24
|
-
this.proxyOptions = options;
|
|
25
|
-
this.proxy = HttpMitmProxy();
|
|
26
|
-
// Inventory repository
|
|
27
|
-
this.inventoryRepository = options.inventoryRepository ?? new InventoryRepository(undefined, this.dependency);
|
|
28
|
-
// Throttle
|
|
29
|
-
if (options.throttle)
|
|
30
|
-
this.throttle = options.throttle;
|
|
31
|
-
this.throttlingRetryIntervalMs = options.throttlingRetryIntervalMs || 10;
|
|
32
|
-
// Entry URL
|
|
33
|
-
this.entryUrl = options.entryUrl;
|
|
34
|
-
// Device type
|
|
35
|
-
this.deviceType = options.deviceType;
|
|
36
|
-
}
|
|
37
|
-
static contextRequest(ctx) {
|
|
38
|
-
if (!ctx.clientToProxyRequest.headers.host)
|
|
39
|
-
throw new Error('ctx.clientToProxyRequest.headers.host is empty');
|
|
40
|
-
const url = [
|
|
41
|
-
ctx.isSSL ? 'https://' : 'http://',
|
|
42
|
-
ctx.clientToProxyRequest.headers.host,
|
|
43
|
-
ctx.clientToProxyRequest.url,
|
|
44
|
-
].join('');
|
|
45
|
-
const method = (ctx.clientToProxyRequest.method || 'get').toLowerCase();
|
|
46
|
-
return {
|
|
47
|
-
method,
|
|
48
|
-
url,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
createThrottlingTransform() {
|
|
52
|
-
if (this.throttle) {
|
|
53
|
-
return new ThrottlingTransform(this.throttle, this.throttlingRetryIntervalMs);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
async start() {
|
|
57
|
-
if (this.throttle)
|
|
58
|
-
this.throttle.start();
|
|
59
|
-
const sslCaDir = this.proxyOptions.sslCaDir || process.env.SSL_CA_DIR || Path.join(Os.homedir(), '.pagespeed-quest/ca');
|
|
60
|
-
const port = Number(this.proxyOptions.port || process.env.PORT || (await GetPort()));
|
|
61
|
-
const options = {
|
|
62
|
-
port,
|
|
63
|
-
sslCaDir,
|
|
64
|
-
httpAgent: new Http.Agent({
|
|
65
|
-
keepAlive: true,
|
|
66
|
-
}),
|
|
67
|
-
httpsAgent: new Https.Agent({
|
|
68
|
-
keepAlive: true,
|
|
69
|
-
secureOptions: Crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
|
|
70
|
-
}),
|
|
71
|
-
};
|
|
72
|
-
await this.setup();
|
|
73
|
-
await Fsp.mkdir(options.sslCaDir, { recursive: true });
|
|
74
|
-
await new Promise((resolve, reject) => this.proxy.listen(options, (error) => (error ? reject(error) : resolve())));
|
|
75
|
-
this.dependency.logger?.info(`Proxy started to listening on port ${this.port}`);
|
|
76
|
-
}
|
|
77
|
-
get port() {
|
|
78
|
-
return this.proxy.httpPort;
|
|
79
|
-
}
|
|
80
|
-
get inventoryDirPath() {
|
|
81
|
-
return this.inventoryRepository.dirPath;
|
|
82
|
-
}
|
|
83
|
-
async stop() {
|
|
84
|
-
this.proxy.close();
|
|
85
|
-
await this.shutdown();
|
|
86
|
-
if (this.throttle)
|
|
87
|
-
this.throttle.stop();
|
|
88
|
-
this.dependency.logger?.info(`Proxy stopped`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
export async function withProxy(proxy, fn) {
|
|
92
|
-
await proxy.start();
|
|
93
|
-
await fn(proxy);
|
|
94
|
-
await proxy.stop();
|
|
95
|
-
}
|
|
96
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFBO0FBQzNCLE9BQU8sR0FBRyxNQUFNLGFBQWEsQ0FBQTtBQUM3QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFDdkIsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFBO0FBQ3pCLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQTtBQUNuQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFFdkIsT0FBTyxPQUFPLE1BQU0sVUFBVSxDQUFBO0FBQzlCLE9BQU8sYUFBYSxNQUFNLGlCQUFpQixDQUFBO0FBRTNDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBQ3BELE9BQU8sRUFBWSxtQkFBbUIsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBYS9ELE1BQU0sT0FBZ0IsS0FBSztJQUN6QixZQUFZLENBQThCO0lBQzFDLEtBQUssQ0FBdUI7SUFDNUIsbUJBQW1CLENBQXNCO0lBQ3pDLFFBQVEsQ0FBVztJQUNuQix5QkFBeUIsQ0FBUztJQUNsQyxRQUFRLENBQVM7SUFDakIsVUFBVSxDQUFhO0lBQ3ZCLFVBQVUsQ0FBaUI7SUFFM0IsWUFBWSxPQUFzQixFQUFFLFVBQTRCO1FBQzlELE9BQU8sS0FBSyxFQUFFLENBQUE7UUFDZCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsSUFBSSxFQUFFLENBQUE7UUFFbEMsUUFBUTtRQUNSLElBQUksQ0FBQyxZQUFZLEdBQUcsT0FBTyxDQUFBO1FBQzNCLElBQUksQ0FBQyxLQUFLLEdBQUcsYUFBYSxFQUFFLENBQUE7UUFFNUIsdUJBQXVCO1FBQ3ZCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxPQUFPLENBQUMsbUJBQW1CLElBQUksSUFBSSxtQkFBbUIsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FB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
|
package/build/throttling.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
|
-
import { Transform, TransformCallback } from 'stream';
|
|
4
|
-
export declare class ThrottlingLog {
|
|
5
|
-
ms: number;
|
|
6
|
-
bytes: number;
|
|
7
|
-
}
|
|
8
|
-
export declare class Throttle {
|
|
9
|
-
flushIntervalMs: number;
|
|
10
|
-
limitBytes: number;
|
|
11
|
-
currentBytes: number;
|
|
12
|
-
interval?: ReturnType<typeof setInterval>;
|
|
13
|
-
logs: ThrottlingLog[];
|
|
14
|
-
constructor(limitBytes: number, flushIntervalMs?: number);
|
|
15
|
-
static fromMbps(mbps: number, flushIntervalMs?: number): Throttle;
|
|
16
|
-
computeCapacity(): {
|
|
17
|
-
consumed: number;
|
|
18
|
-
carryover: number;
|
|
19
|
-
};
|
|
20
|
-
start(): void;
|
|
21
|
-
stop(): void;
|
|
22
|
-
checkAndStack(bytes: number): boolean;
|
|
23
|
-
simpleReport(unitMs?: number): {
|
|
24
|
-
maxBytesPerUnit: number;
|
|
25
|
-
avgBytesPerUnit: number;
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
export declare class ThrottlingTransform extends Transform {
|
|
29
|
-
throttle: Throttle;
|
|
30
|
-
retryIntervalMs: number;
|
|
31
|
-
constructor(throttle: Throttle, retryIntervalMs: number);
|
|
32
|
-
_transform(chunk: string | Buffer, _: string, done: TransformCallback): void;
|
|
33
|
-
}
|
package/build/throttling.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { Transform } from 'stream';
|
|
2
|
-
export class ThrottlingLog {
|
|
3
|
-
ms;
|
|
4
|
-
bytes;
|
|
5
|
-
}
|
|
6
|
-
export class Throttle {
|
|
7
|
-
flushIntervalMs;
|
|
8
|
-
limitBytes;
|
|
9
|
-
currentBytes = 0;
|
|
10
|
-
interval;
|
|
11
|
-
logs = [];
|
|
12
|
-
constructor(limitBytes, flushIntervalMs) {
|
|
13
|
-
this.limitBytes = limitBytes;
|
|
14
|
-
this.flushIntervalMs = flushIntervalMs ?? 100;
|
|
15
|
-
}
|
|
16
|
-
static fromMbps(mbps, flushIntervalMs) {
|
|
17
|
-
const bytesPerSec = (mbps * 1024 * 1024) / 8;
|
|
18
|
-
const limitBytes = Math.floor((bytesPerSec * flushIntervalMs) / 1000);
|
|
19
|
-
return new Throttle(limitBytes, flushIntervalMs);
|
|
20
|
-
}
|
|
21
|
-
computeCapacity() {
|
|
22
|
-
const consumed = Math.min(this.currentBytes, this.limitBytes);
|
|
23
|
-
const carryover = this.currentBytes - consumed;
|
|
24
|
-
return { consumed, carryover };
|
|
25
|
-
}
|
|
26
|
-
start() {
|
|
27
|
-
this.interval = setInterval(() => {
|
|
28
|
-
const c = this.computeCapacity();
|
|
29
|
-
this.logs.push({
|
|
30
|
-
ms: Date.now(),
|
|
31
|
-
bytes: c.consumed,
|
|
32
|
-
});
|
|
33
|
-
this.currentBytes = c.carryover;
|
|
34
|
-
}, this.flushIntervalMs);
|
|
35
|
-
}
|
|
36
|
-
stop() {
|
|
37
|
-
if (this.interval)
|
|
38
|
-
clearInterval(this.interval);
|
|
39
|
-
}
|
|
40
|
-
checkAndStack(bytes) {
|
|
41
|
-
if (!this.interval)
|
|
42
|
-
throw new Error('Throttle is not started');
|
|
43
|
-
if (this.currentBytes >= this.limitBytes) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
this.currentBytes += bytes;
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
simpleReport(unitMs = 1000) {
|
|
50
|
-
const bySec = new Map();
|
|
51
|
-
for (const log of this.logs) {
|
|
52
|
-
const unit = Math.floor(log.ms / unitMs);
|
|
53
|
-
if (!bySec.has(unit))
|
|
54
|
-
bySec.set(unit, 0);
|
|
55
|
-
bySec.set(unit, bySec.get(unit) + log.bytes);
|
|
56
|
-
}
|
|
57
|
-
const values = Array.from(bySec.values());
|
|
58
|
-
const maxBytesPerUnit = Math.max(...values);
|
|
59
|
-
const avgBytesPerUnit = Math.floor(values.reduce((a, b) => a + b, 0) / bySec.size) / 1024 / 1024;
|
|
60
|
-
return {
|
|
61
|
-
maxBytesPerUnit,
|
|
62
|
-
avgBytesPerUnit,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
export class ThrottlingTransform extends Transform {
|
|
67
|
-
throttle;
|
|
68
|
-
retryIntervalMs;
|
|
69
|
-
constructor(throttle, retryIntervalMs) {
|
|
70
|
-
super();
|
|
71
|
-
this.throttle = throttle;
|
|
72
|
-
this.retryIntervalMs = retryIntervalMs;
|
|
73
|
-
}
|
|
74
|
-
_transform(chunk, _, done) {
|
|
75
|
-
if (this.throttle.checkAndStack(chunk.length)) {
|
|
76
|
-
this.push(chunk);
|
|
77
|
-
done();
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const interval = setInterval(() => {
|
|
81
|
-
if (this.throttle.checkAndStack(chunk.length)) {
|
|
82
|
-
clearInterval(interval);
|
|
83
|
-
this.push(chunk);
|
|
84
|
-
done();
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyb3R0bGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90aHJvdHRsaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQXFCLE1BQU0sUUFBUSxDQUFBO0FBRXJELE1BQU0sT0FBTyxhQUFhO0lBQ3hCLEVBQUUsQ0FBUTtJQUNWLEtBQUssQ0FBUTtDQUNkO0FBRUQsTUFBTSxPQUFPLFFBQVE7SUFDbkIsZUFBZSxDQUFTO0lBQ3hCLFVBQVUsQ0FBUztJQUNuQixZQUFZLEdBQUcsQ0FBQyxDQUFBO0lBQ2hCLFFBQVEsQ0FBaUM7SUFDekMsSUFBSSxHQUFvQixFQUFFLENBQUE7SUFFMUIsWUFBWSxVQUFrQixFQUFFLGVBQXdCO1FBQ3RELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFBO1FBQzVCLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxJQUFJLEdBQUcsQ0FBQTtJQUMvQyxDQUFDO0lBRUQsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFZLEVBQUUsZUFBd0I7UUFDcEQsTUFBTSxXQUFXLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUM1QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsV0FBVyxHQUFHLGVBQWUsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFBO1FBQ3JFLE9BQU8sSUFBSSxRQUFRLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBQyxDQUFBO0lBQ2xELENBQUM7SUFFRCxlQUFlO1FBQ2IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUM3RCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxHQUFHLFFBQVEsQ0FBQTtRQUM5QyxPQUFPLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxDQUFBO0lB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
|