bdy 1.8.3-dev → 1.8.4-dev
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/distTs/bin/cli.js +5 -0
- package/distTs/src/agent/linux.js +119 -0
- package/distTs/src/agent/manager.js +395 -0
- package/distTs/src/agent/osx.js +139 -0
- package/distTs/src/agent/socket/tunnel.js +212 -0
- package/distTs/src/agent/socket.js +220 -0
- package/distTs/src/agent/system.js +177 -0
- package/distTs/src/agent/wait.js +23 -0
- package/distTs/src/agent/windows.js +159 -0
- package/distTs/src/agent.js +237 -0
- package/distTs/src/api/agent.js +84 -0
- package/distTs/src/api/buddy.js +117 -0
- package/distTs/src/api/socket.js +133 -0
- package/distTs/src/cfg.js +238 -0
- package/distTs/src/command/agent/install.js +106 -0
- package/distTs/src/command/agent/restart.js +27 -0
- package/distTs/src/command/agent/run.js +19 -0
- package/distTs/src/command/agent/start.js +28 -0
- package/distTs/src/command/agent/status.js +35 -0
- package/distTs/src/command/agent/stop.js +28 -0
- package/distTs/src/command/agent/tunnel/http.js +44 -0
- package/distTs/src/command/agent/tunnel/list.js +27 -0
- package/distTs/src/command/agent/tunnel/remove.js +28 -0
- package/distTs/src/command/agent/tunnel/start.js +34 -0
- package/distTs/src/command/agent/tunnel/status.js +31 -0
- package/distTs/src/command/agent/tunnel/tcp.js +43 -0
- package/distTs/src/command/agent/tunnel/tls.js +43 -0
- package/distTs/src/command/agent/tunnel.js +23 -0
- package/distTs/src/command/agent/uninstall.js +38 -0
- package/distTs/src/command/agent/update.js +38 -0
- package/distTs/src/command/agent/version.js +21 -0
- package/distTs/src/command/agent.js +29 -0
- package/distTs/src/command/config/add/http.js +25 -0
- package/distTs/src/command/config/add/tcp.js +25 -0
- package/distTs/src/command/config/add/tls.js +25 -0
- package/distTs/src/command/config/add.js +15 -0
- package/distTs/src/command/config/get/region.js +15 -0
- package/distTs/src/command/config/get/timeout.js +15 -0
- package/distTs/src/command/config/get/token.js +15 -0
- package/distTs/src/command/config/get/tunnel.js +19 -0
- package/distTs/src/command/config/get/tunnels.js +15 -0
- package/distTs/src/command/config/get/whitelist.js +15 -0
- package/distTs/src/command/config/get.js +21 -0
- package/distTs/src/command/config/remove/tunnel.js +19 -0
- package/distTs/src/command/config/remove.js +11 -0
- package/distTs/src/command/config/set/region.js +17 -0
- package/distTs/src/command/config/set/timeout.js +17 -0
- package/distTs/src/command/config/set/token.js +16 -0
- package/distTs/src/command/config/set/whitelist.js +17 -0
- package/distTs/src/command/config/set.js +17 -0
- package/distTs/src/command/config.js +17 -0
- package/distTs/src/command/http.js +30 -0
- package/distTs/src/command/pre.js +49 -0
- package/distTs/src/command/start.js +28 -0
- package/distTs/src/command/tcp.js +30 -0
- package/distTs/src/command/tls.js +30 -0
- package/distTs/src/command/version.js +13 -0
- package/distTs/src/command/vt/close.js +28 -0
- package/distTs/src/command/vt/exec.js +79 -0
- package/distTs/src/command/vt/storybook.js +90 -0
- package/distTs/src/command/vt.js +15 -0
- package/distTs/src/format.js +172 -0
- package/distTs/src/index.js +40 -0
- package/distTs/src/input.js +286 -0
- package/distTs/src/logger.js +93 -0
- package/distTs/src/output/interactive/tunnel.js +860 -0
- package/distTs/src/output/noninteractive/agent/tunnels.js +43 -0
- package/distTs/src/output/noninteractive/config/tunnel.js +67 -0
- package/distTs/src/output/noninteractive/config/tunnels.js +18 -0
- package/distTs/src/output/noninteractive/tunnel.js +59 -0
- package/distTs/src/output.js +138 -0
- package/distTs/src/server/cert.js +52 -0
- package/distTs/src/server/http1.js +74 -0
- package/distTs/src/server/http2.js +74 -0
- package/distTs/src/server/sftp.js +487 -0
- package/distTs/src/server/ssh.js +112 -0
- package/distTs/src/server/tls.js +41 -0
- package/distTs/src/ssh/client.js +191 -0
- package/distTs/src/texts.js +345 -0
- package/distTs/src/tunnel/agent.js +100 -0
- package/distTs/src/tunnel/compression.js +41 -0
- package/distTs/src/tunnel/dns.js +54 -0
- package/distTs/src/tunnel/html.js +30 -0
- package/distTs/src/tunnel/http/log.js +196 -0
- package/distTs/src/tunnel/http/serve.js +132 -0
- package/distTs/src/tunnel/http/stream.js +45 -0
- package/distTs/src/tunnel/http.js +405 -0
- package/distTs/src/tunnel/identification.js +96 -0
- package/distTs/src/tunnel/latency.js +71 -0
- package/distTs/src/tunnel/tcp.js +92 -0
- package/distTs/src/tunnel.js +647 -0
- package/distTs/src/types/ciInfo.js +10 -0
- package/distTs/src/types/options.js +2 -0
- package/distTs/src/types/plugin.js +2 -0
- package/distTs/src/types/queue.js +2 -0
- package/distTs/src/types/requests.js +2 -0
- package/distTs/src/types/resources.js +2 -0
- package/distTs/src/types/snapshots.js +2 -0
- package/distTs/src/types/storybook.js +2 -0
- package/distTs/src/utils.js +437 -0
- package/distTs/src/visualTest/browser.js +32 -0
- package/distTs/src/visualTest/ci.js +206 -0
- package/distTs/src/visualTest/context.js +44 -0
- package/distTs/src/visualTest/exec.js +51 -0
- package/distTs/src/visualTest/queue.js +43 -0
- package/distTs/src/visualTest/requests.js +197 -0
- package/distTs/src/visualTest/resources.js +195 -0
- package/distTs/src/visualTest/server.js +33 -0
- package/distTs/src/visualTest/snapshots.js +109 -0
- package/distTs/src/visualTest/utils/parseDom.js +238 -0
- package/distTs/src/visualTest/validation.js +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.debug = exports.browserPath = exports.commitDetails = exports.invokerId = exports.executionId = exports.actionId = exports.pipelineId = exports.baseCommit = exports.commit = exports.branch = exports.ci = exports.buildId = exports.token = exports.parallel = exports.skipDiscovery = exports.oneByOne = exports.cliVersion = void 0;
|
|
4
|
+
exports.setOptions = setOptions;
|
|
5
|
+
exports.setBrowserPath = setBrowserPath;
|
|
6
|
+
exports.setCiAndCommitInfo = setCiAndCommitInfo;
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
const ciInfo_js_1 = require("../types/ciInfo.js");
|
|
9
|
+
const utils_1 = require("../utils");
|
|
10
|
+
exports.cliVersion = (0, utils_1.getVersion)();
|
|
11
|
+
exports.oneByOne = false;
|
|
12
|
+
exports.skipDiscovery = false;
|
|
13
|
+
exports.parallel = false;
|
|
14
|
+
exports.token = process.env.SNAPSHOTS_TOKEN || '';
|
|
15
|
+
exports.buildId = process.env.SNAPSHOTS_BUILD_ID || (0, uuid_1.v4)();
|
|
16
|
+
exports.ci = ciInfo_js_1.CI.NONE;
|
|
17
|
+
exports.debug = (process.env.SNAPSHOTS_DEBUG || '').toLowerCase() === 'true';
|
|
18
|
+
function setOptions(options) {
|
|
19
|
+
if (options.oneByOne) {
|
|
20
|
+
exports.oneByOne = true;
|
|
21
|
+
}
|
|
22
|
+
if (options.skipDiscovery) {
|
|
23
|
+
exports.skipDiscovery = true;
|
|
24
|
+
}
|
|
25
|
+
if (options.parallel) {
|
|
26
|
+
exports.parallel = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function setBrowserPath(path) {
|
|
30
|
+
exports.browserPath = path;
|
|
31
|
+
}
|
|
32
|
+
function setCiAndCommitInfo(ciInfo) {
|
|
33
|
+
exports.ci = ciInfo.ci;
|
|
34
|
+
exports.branch = ciInfo.branch;
|
|
35
|
+
exports.commit = ciInfo.commit;
|
|
36
|
+
exports.baseCommit = ciInfo.baseCommit;
|
|
37
|
+
exports.commitDetails = ciInfo.commitDetails;
|
|
38
|
+
if (ciInfo.ci === ciInfo_js_1.CI.BUDDY) {
|
|
39
|
+
exports.pipelineId = ciInfo.pipelineId;
|
|
40
|
+
exports.actionId = ciInfo.actionId;
|
|
41
|
+
exports.executionId = ciInfo.executionId;
|
|
42
|
+
exports.invokerId = ciInfo.invokerId;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.testExec = testExec;
|
|
7
|
+
exports.gitExec = gitExec;
|
|
8
|
+
const cross_spawn_1 = require("cross-spawn");
|
|
9
|
+
const output_1 = __importDefault(require("../output"));
|
|
10
|
+
const texts_1 = require("../texts");
|
|
11
|
+
function testExec(command, arguments_) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const process = (0, cross_spawn_1.spawn)(command, arguments_, { stdio: 'inherit' });
|
|
14
|
+
let processError;
|
|
15
|
+
process.on('error', (error) => {
|
|
16
|
+
output_1.default.error(texts_1.ERR_TEST_EXECUTION);
|
|
17
|
+
processError = error;
|
|
18
|
+
});
|
|
19
|
+
process.on('close', (code) => {
|
|
20
|
+
if (processError) {
|
|
21
|
+
reject(processError);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
resolve(code || 0);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function gitExec(arguments_) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const process = (0, cross_spawn_1.spawn)('git', arguments_, {
|
|
32
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
33
|
+
});
|
|
34
|
+
let errorOutput = '';
|
|
35
|
+
let output = '';
|
|
36
|
+
process.stdout.on('data', (message) => {
|
|
37
|
+
output += message;
|
|
38
|
+
});
|
|
39
|
+
process.stderr.on('data', (message) => {
|
|
40
|
+
errorOutput += message;
|
|
41
|
+
});
|
|
42
|
+
process.on('close', (code) => {
|
|
43
|
+
if (code === 0) {
|
|
44
|
+
resolve(output);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
reject(errorOutput);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addToQueue = addToQueue;
|
|
4
|
+
exports.isQueueEmpty = isQueueEmpty;
|
|
5
|
+
const queue = [];
|
|
6
|
+
const observers = [];
|
|
7
|
+
let processing = false;
|
|
8
|
+
function addToQueue(job) {
|
|
9
|
+
queue.push(job);
|
|
10
|
+
if (!processing) {
|
|
11
|
+
processQueue();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function processQueue() {
|
|
15
|
+
const task = queue.shift();
|
|
16
|
+
if (task) {
|
|
17
|
+
processing = true;
|
|
18
|
+
task().then(() => {
|
|
19
|
+
if (queue.length > 0) {
|
|
20
|
+
processQueue();
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
processing = false;
|
|
24
|
+
signalStopProcessing();
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function subscribeToStopProcessing(function_) {
|
|
30
|
+
observers.push(function_);
|
|
31
|
+
}
|
|
32
|
+
function signalStopProcessing() {
|
|
33
|
+
for (const observer of observers) {
|
|
34
|
+
observer();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function isQueueEmpty() {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
subscribeToStopProcessing(() => {
|
|
40
|
+
resolve(true);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.sendSnapshot = sendSnapshot;
|
|
7
|
+
exports.sendSnapshots = sendSnapshots;
|
|
8
|
+
exports.closeSession = closeSession;
|
|
9
|
+
exports.getDefaultSettings = getDefaultSettings;
|
|
10
|
+
exports.sendStorybook = sendStorybook;
|
|
11
|
+
const context_js_1 = require("./context.js");
|
|
12
|
+
const undici_1 = require("undici");
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
const node_fs_1 = require("node:fs");
|
|
15
|
+
const output_1 = __importDefault(require("../output"));
|
|
16
|
+
const texts_1 = require("../texts");
|
|
17
|
+
const serviceUrl = process.env.SNAPSHOTS_SERVICE_URL || 'http://localhost:3000';
|
|
18
|
+
function filterSnapshotPlugin(snapshot) {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
const { resourceDiscoveryTimeout, cookies, ...filteredSnapshot } = snapshot;
|
|
21
|
+
return filteredSnapshot;
|
|
22
|
+
}
|
|
23
|
+
function convertTextToBlob(text, headers) {
|
|
24
|
+
if (headers['content-type']?.includes('image')) {
|
|
25
|
+
const buffer = Buffer.from(text, 'base64');
|
|
26
|
+
return new Blob([buffer]);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return new Blob([text]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function prepareSnapshot(snapshot, files) {
|
|
33
|
+
return {
|
|
34
|
+
...filterSnapshotPlugin(snapshot),
|
|
35
|
+
resources: snapshot.resources.map((resource) => {
|
|
36
|
+
const { body, headers, ...rest } = resource;
|
|
37
|
+
if (body) {
|
|
38
|
+
const id = (0, uuid_1.v4)();
|
|
39
|
+
const preparedBody = typeof body === 'string' ? convertTextToBlob(body, headers) : body;
|
|
40
|
+
files.push({ id, body: preparedBody });
|
|
41
|
+
return { ...rest, headers, id };
|
|
42
|
+
}
|
|
43
|
+
return resource;
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function createFormData(info, files) {
|
|
48
|
+
const formData = new undici_1.FormData();
|
|
49
|
+
formData.append('info', JSON.stringify(info));
|
|
50
|
+
for (const { id, body } of files) {
|
|
51
|
+
formData.append(id, body);
|
|
52
|
+
}
|
|
53
|
+
return formData;
|
|
54
|
+
}
|
|
55
|
+
async function sendSnapshot(snapshot) {
|
|
56
|
+
const files = [];
|
|
57
|
+
const preparedSnapshot = prepareSnapshot(snapshot, files);
|
|
58
|
+
const info = {
|
|
59
|
+
snapshot: preparedSnapshot,
|
|
60
|
+
token: context_js_1.token,
|
|
61
|
+
buildId: context_js_1.buildId,
|
|
62
|
+
cliVersion: context_js_1.cliVersion,
|
|
63
|
+
parallel: context_js_1.parallel,
|
|
64
|
+
ci: context_js_1.ci,
|
|
65
|
+
branch: context_js_1.branch,
|
|
66
|
+
commit: context_js_1.commit,
|
|
67
|
+
baseCommit: context_js_1.baseCommit,
|
|
68
|
+
pipelineId: context_js_1.pipelineId,
|
|
69
|
+
actionId: context_js_1.actionId,
|
|
70
|
+
executionId: context_js_1.executionId,
|
|
71
|
+
invokerId: context_js_1.invokerId,
|
|
72
|
+
commitDetails: context_js_1.commitDetails,
|
|
73
|
+
};
|
|
74
|
+
const formData = createFormData(info, files);
|
|
75
|
+
const [message] = await sendRequest({
|
|
76
|
+
url: '/snapshot',
|
|
77
|
+
payload: formData,
|
|
78
|
+
multipart: true,
|
|
79
|
+
});
|
|
80
|
+
if (!message) {
|
|
81
|
+
throw new Error(texts_1.ERR_INVALID_SNAPSHOT_RESPONSE);
|
|
82
|
+
}
|
|
83
|
+
return message;
|
|
84
|
+
}
|
|
85
|
+
async function sendSnapshots(snapshots) {
|
|
86
|
+
const files = [];
|
|
87
|
+
const preparedSnapshots = snapshots.map((snapshot) => prepareSnapshot(snapshot, files));
|
|
88
|
+
const info = {
|
|
89
|
+
snapshots: preparedSnapshots,
|
|
90
|
+
token: context_js_1.token,
|
|
91
|
+
buildId: context_js_1.buildId,
|
|
92
|
+
cliVersion: context_js_1.cliVersion,
|
|
93
|
+
parallel: context_js_1.parallel,
|
|
94
|
+
ci: context_js_1.ci,
|
|
95
|
+
branch: context_js_1.branch,
|
|
96
|
+
commit: context_js_1.commit,
|
|
97
|
+
baseCommit: context_js_1.baseCommit,
|
|
98
|
+
pipelineId: context_js_1.pipelineId,
|
|
99
|
+
actionId: context_js_1.actionId,
|
|
100
|
+
executionId: context_js_1.executionId,
|
|
101
|
+
invokerId: context_js_1.invokerId,
|
|
102
|
+
commitDetails: context_js_1.commitDetails,
|
|
103
|
+
};
|
|
104
|
+
const formData = createFormData(info, files);
|
|
105
|
+
const [message] = await sendRequest({
|
|
106
|
+
url: '/snapshots',
|
|
107
|
+
payload: formData,
|
|
108
|
+
multipart: true,
|
|
109
|
+
});
|
|
110
|
+
if (!message) {
|
|
111
|
+
throw new Error(texts_1.ERR_INVALID_SNAPSHOTS_RESPONSE);
|
|
112
|
+
}
|
|
113
|
+
return message;
|
|
114
|
+
}
|
|
115
|
+
async function closeSession() {
|
|
116
|
+
const payload = {
|
|
117
|
+
token: context_js_1.token,
|
|
118
|
+
buildId: context_js_1.buildId,
|
|
119
|
+
};
|
|
120
|
+
const [message] = await sendRequest({ url: '/close', payload });
|
|
121
|
+
if (!message) {
|
|
122
|
+
throw new Error(texts_1.ERR_INVALID_CLOSE_SESSION_RESPONSE);
|
|
123
|
+
}
|
|
124
|
+
return message;
|
|
125
|
+
}
|
|
126
|
+
async function getDefaultSettings() {
|
|
127
|
+
const [message, response] = await sendRequest({
|
|
128
|
+
url: `/defaultSettings?token=${context_js_1.token}`,
|
|
129
|
+
});
|
|
130
|
+
if (message) {
|
|
131
|
+
throw new Error(message);
|
|
132
|
+
}
|
|
133
|
+
if (!response) {
|
|
134
|
+
throw new Error(texts_1.ERR_INVALID_DEFAULT_SETTINGS_RESPONSE);
|
|
135
|
+
}
|
|
136
|
+
return response;
|
|
137
|
+
}
|
|
138
|
+
async function sendStorybook(snapshots, filePaths) {
|
|
139
|
+
const info = {
|
|
140
|
+
snapshots,
|
|
141
|
+
token: context_js_1.token,
|
|
142
|
+
buildId: context_js_1.buildId,
|
|
143
|
+
cliVersion: context_js_1.cliVersion,
|
|
144
|
+
ci: context_js_1.ci,
|
|
145
|
+
branch: context_js_1.branch,
|
|
146
|
+
commit: context_js_1.commit,
|
|
147
|
+
baseCommit: context_js_1.baseCommit,
|
|
148
|
+
pipelineId: context_js_1.pipelineId,
|
|
149
|
+
actionId: context_js_1.actionId,
|
|
150
|
+
executionId: context_js_1.executionId,
|
|
151
|
+
invokerId: context_js_1.invokerId,
|
|
152
|
+
commitDetails: context_js_1.commitDetails,
|
|
153
|
+
};
|
|
154
|
+
const files = filePaths.map((file) => ({
|
|
155
|
+
id: file,
|
|
156
|
+
body: new Blob([(0, node_fs_1.readFileSync)(file)]),
|
|
157
|
+
}));
|
|
158
|
+
const formData = createFormData(info, files);
|
|
159
|
+
const [message] = await sendRequest({
|
|
160
|
+
url: '/storybook',
|
|
161
|
+
payload: formData,
|
|
162
|
+
multipart: true,
|
|
163
|
+
});
|
|
164
|
+
if (!message) {
|
|
165
|
+
throw new Error(texts_1.ERR_INVALID_STORYBOOK_RESPONSE);
|
|
166
|
+
}
|
|
167
|
+
return message;
|
|
168
|
+
}
|
|
169
|
+
async function sendRequest({ url, payload, multipart, }) {
|
|
170
|
+
output_1.default.normal((0, texts_1.LOG_SENDING_REQUEST)(`${serviceUrl}${url}`));
|
|
171
|
+
const init = {
|
|
172
|
+
method: 'GET',
|
|
173
|
+
redirect: 'follow',
|
|
174
|
+
};
|
|
175
|
+
if (payload && !multipart) {
|
|
176
|
+
init.method = 'POST';
|
|
177
|
+
init.headers = { 'Content-Type': 'application/json' };
|
|
178
|
+
init.body = JSON.stringify(payload);
|
|
179
|
+
}
|
|
180
|
+
if (multipart) {
|
|
181
|
+
init.method = 'POST';
|
|
182
|
+
init.body = payload;
|
|
183
|
+
}
|
|
184
|
+
const response = await (0, undici_1.fetch)(`${serviceUrl}${url}`, init);
|
|
185
|
+
const contentType = response.headers.get('content-type');
|
|
186
|
+
if (contentType && contentType.includes('application/json')) {
|
|
187
|
+
try {
|
|
188
|
+
const json = (await response.json());
|
|
189
|
+
return [undefined, json];
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
throw new Error(texts_1.ERR_INVALID_JSON);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const text = await response.text();
|
|
196
|
+
return [text, undefined];
|
|
197
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.collectResources = collectResources;
|
|
7
|
+
const puppeteer_core_1 = __importDefault(require("puppeteer-core"));
|
|
8
|
+
const context_js_1 = require("./context.js");
|
|
9
|
+
const output_1 = __importDefault(require("../output"));
|
|
10
|
+
const texts_1 = require("../texts");
|
|
11
|
+
const scrapedUrls = new Map();
|
|
12
|
+
const scrapedResources = new Map();
|
|
13
|
+
async function collectResources({ url, widths = [1280], resourceDiscoveryTimeout = 0, height = 1024, cookies, scaleRatio, }) {
|
|
14
|
+
const scrapedUrl = scrapedUrls.get(url);
|
|
15
|
+
const missingWidths = scrapedUrl
|
|
16
|
+
? widths.filter((width) => !scrapedUrl.widths.includes(width))
|
|
17
|
+
: [];
|
|
18
|
+
if (scrapedUrl && missingWidths.length === 0) {
|
|
19
|
+
return getResourceUrlsData({
|
|
20
|
+
duplicatedResourcesUrls: scrapedUrl.resources,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
else if (scrapedUrl && missingWidths.length > 0) {
|
|
24
|
+
const { scrapedResourcesUrls, duplicatedResourcesUrls } = await output_1.default.debug((0, texts_1.DEBUG_RESOURCE_SCRAPPING_URL)(url), scrapeResources({
|
|
25
|
+
url,
|
|
26
|
+
widths: missingWidths,
|
|
27
|
+
height,
|
|
28
|
+
resourceDiscoveryTimeout,
|
|
29
|
+
cookies,
|
|
30
|
+
scaleRatio,
|
|
31
|
+
}));
|
|
32
|
+
const duplicatedScrapedResourceUrls = [...scrapedUrl.resources];
|
|
33
|
+
scrapedUrls.set(url, {
|
|
34
|
+
widths: [...scrapedUrl.widths, ...missingWidths],
|
|
35
|
+
resources: [
|
|
36
|
+
...new Set([
|
|
37
|
+
...scrapedUrl.resources,
|
|
38
|
+
...scrapedResourcesUrls,
|
|
39
|
+
...duplicatedResourcesUrls,
|
|
40
|
+
]),
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
return getResourceUrlsData({
|
|
44
|
+
resourcesUrls: scrapedResourcesUrls,
|
|
45
|
+
duplicatedResourcesUrls: [
|
|
46
|
+
...new Set([
|
|
47
|
+
...duplicatedResourcesUrls,
|
|
48
|
+
...duplicatedScrapedResourceUrls,
|
|
49
|
+
]),
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const { scrapedResourcesUrls, duplicatedResourcesUrls } = await output_1.default.debug((0, texts_1.DEBUG_RESOURCE_SCRAPPING_URL)(url), scrapeResources({
|
|
55
|
+
url,
|
|
56
|
+
widths,
|
|
57
|
+
height,
|
|
58
|
+
resourceDiscoveryTimeout,
|
|
59
|
+
cookies,
|
|
60
|
+
scaleRatio,
|
|
61
|
+
}));
|
|
62
|
+
scrapedUrls.set(url, {
|
|
63
|
+
widths,
|
|
64
|
+
resources: [...scrapedResourcesUrls, ...duplicatedResourcesUrls],
|
|
65
|
+
});
|
|
66
|
+
return getResourceUrlsData({
|
|
67
|
+
resourcesUrls: scrapedResourcesUrls,
|
|
68
|
+
duplicatedResourcesUrls,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getResourceUrlsData({ resourcesUrls = [], duplicatedResourcesUrls = [], }) {
|
|
73
|
+
const resources = [];
|
|
74
|
+
for (const resourceUrl of resourcesUrls) {
|
|
75
|
+
const scrapedResource = scrapedResources.get(resourceUrl);
|
|
76
|
+
if (scrapedResource) {
|
|
77
|
+
resources.push({
|
|
78
|
+
url: resourceUrl,
|
|
79
|
+
status: scrapedResource.status,
|
|
80
|
+
headers: scrapedResource.headers,
|
|
81
|
+
body: scrapedResource.body,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw new Error((0, texts_1.ERR_RESOURCE_NOT_FOUND)(resourceUrl));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const resourceUrl of duplicatedResourcesUrls) {
|
|
89
|
+
const scrapedResource = scrapedResources.get(resourceUrl);
|
|
90
|
+
if (scrapedResource) {
|
|
91
|
+
resources.push({
|
|
92
|
+
url: resourceUrl,
|
|
93
|
+
status: scrapedResource.status,
|
|
94
|
+
headers: scrapedResource.headers,
|
|
95
|
+
duplicate: true,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
throw new Error((0, texts_1.ERR_RESOURCE_NOT_FOUND)(resourceUrl));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return resources;
|
|
103
|
+
}
|
|
104
|
+
async function scrapeResources({ url, widths, height, resourceDiscoveryTimeout, cookies = [], scaleRatio, }) {
|
|
105
|
+
const scrapedResourcesUrls = [];
|
|
106
|
+
const duplicatedResourcesUrls = [];
|
|
107
|
+
const launchOptions = {
|
|
108
|
+
headless: 'shell',
|
|
109
|
+
args: ['--no-sandbox'],
|
|
110
|
+
acceptInsecureCerts: true,
|
|
111
|
+
timeout: 120_000,
|
|
112
|
+
executablePath: context_js_1.browserPath,
|
|
113
|
+
};
|
|
114
|
+
const browser = await puppeteer_core_1.default.launch(launchOptions);
|
|
115
|
+
const page = await browser.newPage();
|
|
116
|
+
const initWidth = widths[0];
|
|
117
|
+
await page.setViewport({
|
|
118
|
+
width: initWidth,
|
|
119
|
+
height,
|
|
120
|
+
deviceScaleFactor: scaleRatio,
|
|
121
|
+
});
|
|
122
|
+
await page.setCookie(...cookies);
|
|
123
|
+
page.on('response', async (response) => {
|
|
124
|
+
const request = response.request();
|
|
125
|
+
const requestUrl = request.url();
|
|
126
|
+
const isCollected = scrapedResources.has(requestUrl);
|
|
127
|
+
if (isCollected && !scrapedResourcesUrls.includes(requestUrl)) {
|
|
128
|
+
duplicatedResourcesUrls.push(requestUrl);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
let responseError;
|
|
132
|
+
let body;
|
|
133
|
+
const requestUrl = request.url();
|
|
134
|
+
const headers = response.headers();
|
|
135
|
+
const contentType = headers['content-type'];
|
|
136
|
+
const status = response.status();
|
|
137
|
+
try {
|
|
138
|
+
if ((status < 300 || status > 399) &&
|
|
139
|
+
!contentType.startsWith('text/html')) {
|
|
140
|
+
body = new Blob([await response.buffer()]);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
responseError = error;
|
|
145
|
+
}
|
|
146
|
+
if (!responseError && body) {
|
|
147
|
+
scrapedResourcesUrls.push(requestUrl);
|
|
148
|
+
scrapedResources.set(requestUrl, {
|
|
149
|
+
status,
|
|
150
|
+
headers: { 'content-type': contentType },
|
|
151
|
+
body,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
await page.goto(url);
|
|
157
|
+
await output_1.default.debug(texts_1.DEBUG_AUTO_SCROLL, autoScroll(page));
|
|
158
|
+
await output_1.default.debug(texts_1.DEBUG_AUTO_WIDTH, autoWidths(page, widths, height));
|
|
159
|
+
if (resourceDiscoveryTimeout > 0) {
|
|
160
|
+
await new Promise((resolve) => setTimeout(resolve, resourceDiscoveryTimeout));
|
|
161
|
+
if (context_js_1.debug) {
|
|
162
|
+
output_1.default.warning((0, texts_1.DEBUG_RESOURCE_DISCOVERY_TIMEOUT)(resourceDiscoveryTimeout));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
await output_1.default.debug(texts_1.DEBUG_WAIT_FOR_IDLE, page.waitForNetworkIdle());
|
|
166
|
+
await browser.close();
|
|
167
|
+
return { scrapedResourcesUrls, duplicatedResourcesUrls };
|
|
168
|
+
}
|
|
169
|
+
async function autoScroll(page) {
|
|
170
|
+
await page.evaluate(async () => {
|
|
171
|
+
await new Promise((resolve) => {
|
|
172
|
+
const resourceDiscoveryMaxHeight = 30_000;
|
|
173
|
+
let totalHeight = 0;
|
|
174
|
+
const distance = 100;
|
|
175
|
+
const timer = setInterval(() => {
|
|
176
|
+
const scrollHeight = document.body.scrollHeight;
|
|
177
|
+
window.scrollBy(0, distance);
|
|
178
|
+
totalHeight += distance;
|
|
179
|
+
if (totalHeight >=
|
|
180
|
+
(scrollHeight - window.innerHeight || resourceDiscoveryMaxHeight)) {
|
|
181
|
+
clearInterval(timer);
|
|
182
|
+
resolve('');
|
|
183
|
+
}
|
|
184
|
+
}, 10);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async function autoWidths(page, widths, height) {
|
|
189
|
+
for (const width of widths) {
|
|
190
|
+
if (width !== widths[0]) {
|
|
191
|
+
await page.setViewport({ width, height, deviceScaleFactor: 2 });
|
|
192
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createServer = createServer;
|
|
7
|
+
const fastify_1 = __importDefault(require("fastify"));
|
|
8
|
+
const cors_1 = __importDefault(require("@fastify/cors"));
|
|
9
|
+
const snapshots_js_1 = require("./snapshots.js");
|
|
10
|
+
// File will be imported as source text;
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
const parseDom_js_1 = __importDefault(require("./utils/parseDom.js"));
|
|
13
|
+
const port = 1337;
|
|
14
|
+
async function createServer() {
|
|
15
|
+
const app = (0, fastify_1.default)({
|
|
16
|
+
// logger: true,
|
|
17
|
+
bodyLimit: 50 * 1024 * 1024, //50 MB,
|
|
18
|
+
});
|
|
19
|
+
app.register(cors_1.default);
|
|
20
|
+
app.get('/parseDom.js', async (request, reply) => {
|
|
21
|
+
reply.type('text/js').send(parseDom_js_1.default);
|
|
22
|
+
});
|
|
23
|
+
app.post('/snapshot', async (request, reply) => {
|
|
24
|
+
const data = request.body;
|
|
25
|
+
(0, snapshots_js_1.addSnapshot)(data);
|
|
26
|
+
reply.send('Snapshot received');
|
|
27
|
+
});
|
|
28
|
+
app.get('*', (request, reply) => {
|
|
29
|
+
reply.send('Wrong path');
|
|
30
|
+
});
|
|
31
|
+
await app.listen({ port });
|
|
32
|
+
return app;
|
|
33
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.setDefaultSettings = setDefaultSettings;
|
|
7
|
+
exports.addSnapshot = addSnapshot;
|
|
8
|
+
exports.finishProcessingSnapshots = finishProcessingSnapshots;
|
|
9
|
+
const resources_js_1 = require("./resources.js");
|
|
10
|
+
const context_js_1 = require("./context.js");
|
|
11
|
+
const requests_js_1 = require("./requests.js");
|
|
12
|
+
const queue_js_1 = require("./queue.js");
|
|
13
|
+
const output_1 = __importDefault(require("../output"));
|
|
14
|
+
const texts_1 = require("../texts");
|
|
15
|
+
const snapshots = [];
|
|
16
|
+
let defaultWidths = [];
|
|
17
|
+
let defaultScaleRatio = 1;
|
|
18
|
+
function setDefaultSettings({ defaultWidths: width, defaultScaleRatio: scaleRatio, }) {
|
|
19
|
+
defaultWidths = width;
|
|
20
|
+
defaultScaleRatio = scaleRatio;
|
|
21
|
+
}
|
|
22
|
+
function addSnapshot(snapshot) {
|
|
23
|
+
const preparedSnapshots = {
|
|
24
|
+
...snapshot,
|
|
25
|
+
widths: snapshot.widths.length > 0 ? snapshot.widths : defaultWidths,
|
|
26
|
+
scaleRatio: defaultScaleRatio,
|
|
27
|
+
};
|
|
28
|
+
if (context_js_1.oneByOne) {
|
|
29
|
+
(0, queue_js_1.addToQueue)(() => processSnapshot(preparedSnapshots));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
snapshots.push(preparedSnapshots);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function finishProcessingSnapshots(spawnedProcessExitCode) {
|
|
36
|
+
if (context_js_1.oneByOne) {
|
|
37
|
+
return await (0, queue_js_1.isQueueEmpty)();
|
|
38
|
+
}
|
|
39
|
+
if (spawnedProcessExitCode === 0) {
|
|
40
|
+
return await processSnapshots();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function processSnapshot(snapshot) {
|
|
44
|
+
let t1;
|
|
45
|
+
if (context_js_1.debug) {
|
|
46
|
+
t1 = performance.now();
|
|
47
|
+
}
|
|
48
|
+
const preparedSnapshot = context_js_1.skipDiscovery
|
|
49
|
+
? snapshot
|
|
50
|
+
: await getSnapshotWithResources(snapshot);
|
|
51
|
+
try {
|
|
52
|
+
const response = await (0, requests_js_1.sendSnapshot)(preparedSnapshot);
|
|
53
|
+
output_1.default.normal(response);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
output_1.default.error(`${error}`);
|
|
57
|
+
}
|
|
58
|
+
if (context_js_1.debug && t1) {
|
|
59
|
+
const t2 = performance.now();
|
|
60
|
+
output_1.default.normal((0, texts_1.DEBUG_SNAPSHOT_PROCESSING)(snapshot.name, t2 - t1));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function processSnapshots() {
|
|
64
|
+
let t1;
|
|
65
|
+
if (context_js_1.debug) {
|
|
66
|
+
t1 = performance.now();
|
|
67
|
+
}
|
|
68
|
+
output_1.default.normal((0, texts_1.LOG_PROCESSING_SNAPSHOTS)(snapshots.length));
|
|
69
|
+
const preparedSnapshots = context_js_1.skipDiscovery
|
|
70
|
+
? snapshots
|
|
71
|
+
: await getSnapshotsWithResources(snapshots);
|
|
72
|
+
try {
|
|
73
|
+
const response = await (0, requests_js_1.sendSnapshots)(preparedSnapshots);
|
|
74
|
+
output_1.default.normal(response);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
output_1.default.error(`${error}`);
|
|
78
|
+
}
|
|
79
|
+
if (context_js_1.debug && t1) {
|
|
80
|
+
const t2 = performance.now();
|
|
81
|
+
output_1.default.normal((0, texts_1.DEBUG_SNAPSHOTS_PROCESSING)(t2 - t1));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function getSnapshotWithResources(snapshot) {
|
|
85
|
+
const { url, widths, resourceDiscoveryTimeout, cookies, scaleRatio } = snapshot;
|
|
86
|
+
const resources = await (0, resources_js_1.collectResources)({
|
|
87
|
+
url,
|
|
88
|
+
widths,
|
|
89
|
+
resourceDiscoveryTimeout,
|
|
90
|
+
cookies,
|
|
91
|
+
scaleRatio,
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
...snapshot,
|
|
95
|
+
resources: [...snapshot.resources, ...resources],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function getSnapshotsWithResources(snapshots) {
|
|
99
|
+
const snapshotsWithResources = [];
|
|
100
|
+
const prepareSnapshots = filterDuplicates(snapshots);
|
|
101
|
+
for (const snapshot of prepareSnapshots) {
|
|
102
|
+
const snapshotWithResources = await getSnapshotWithResources(snapshot);
|
|
103
|
+
snapshotsWithResources.push(snapshotWithResources);
|
|
104
|
+
}
|
|
105
|
+
return snapshotsWithResources;
|
|
106
|
+
}
|
|
107
|
+
function filterDuplicates(snapshots) {
|
|
108
|
+
return snapshots.filter((snapshot, index) => snapshots.findIndex((item) => item.name === snapshot.name) === index);
|
|
109
|
+
}
|