@speedkit/cli 3.21.0 → 3.23.0
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/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/dist/services/customer-config/templates/config_loadHandler.js.hbs +5 -2
- package/dist/services/document-handler-runtime/document-handler-server.js +1 -1
- package/dist/services/onboarding/onboarding-model.d.ts +2 -0
- package/dist/services/onboarding/onboarding-service-factory.d.ts +2 -0
- package/dist/services/onboarding/onboarding-service-factory.js +42 -1
- package/dist/services/onboarding/virtual-orestes-app/crawler.d.ts +3 -1
- package/dist/services/onboarding/virtual-orestes-app/crawler.js +22 -18
- package/dist/services/onboarding/virtual-orestes-app/index.js +12 -12
- package/oclif.manifest.json +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# [3.23.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.22.0...v3.23.0) (2026-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **customer-config:** add a timeout to wait for potential click listeners to be completed ([36aba47](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/36aba475854d8a873a31a464c5e0e68302d2cdd9))
|
|
7
|
+
* **customer-config:** include comment about hard navigation execution ([f0fdac6](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/f0fdac631a90e818e6ed4ce3d9b3c8482df3f3aa))
|
|
8
|
+
|
|
9
|
+
# [3.22.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.21.0...v3.22.0) (2026-01-30)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* add socksConnector to run localDocHandler in proxyMode ([eb3d3a2](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/eb3d3a2ce197aad600506df38032ba6e1fc25594))
|
|
15
|
+
* set correct variations ([6021e22](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/6021e2258a9afe61ee9fced046d1f944b0134d57))
|
|
16
|
+
* update crawler for docHandler to respect variations ([5880526](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/58805265156bde07b61bcb5599dd19cacffc7680))
|
|
17
|
+
|
|
1
18
|
# [3.21.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.20.0...v3.21.0) (2026-01-30)
|
|
2
19
|
|
|
3
20
|
|
package/README.md
CHANGED
|
@@ -449,9 +449,12 @@ import { PredictivePreloading } from 'predictive-preloading/predictivePreloading
|
|
|
449
449
|
|
|
450
450
|
// Prevent soft navigation
|
|
451
451
|
event.preventDefault();
|
|
452
|
+
setTimeout(() => {
|
|
453
|
+
// let potential click listener be completed
|
|
452
454
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
+
//Execute hard navigation instead
|
|
456
|
+
location.href = target.href;
|
|
457
|
+
});
|
|
455
458
|
}
|
|
456
459
|
window.addEventListener("click", speedKitClickEventListener, true);
|
|
457
460
|
}
|
|
@@ -190,7 +190,7 @@ class DocumentHandlerServer {
|
|
|
190
190
|
if (module === "baqend") {
|
|
191
191
|
return { baqend: { message: { RevalidateAssets: () => true } } };
|
|
192
192
|
}
|
|
193
|
-
if (module.includes("fetch")) {
|
|
193
|
+
if (module.toLowerCase().includes("fetch")) {
|
|
194
194
|
return this.createFetchMock();
|
|
195
195
|
}
|
|
196
196
|
const fileExtension = node_path_1.default.extname(module);
|
|
@@ -43,6 +43,8 @@ const static_recipe_1 = require("../integration-api/virtual/static-recipe");
|
|
|
43
43
|
const diff_against_current_page_1 = require("./dashboard/diff-against-current-page");
|
|
44
44
|
const extension_downloader_1 = require("./browser/extension/extension-downloader");
|
|
45
45
|
const executable_validator_1 = require("./browser/executable/executable-validator");
|
|
46
|
+
const fetch_socks_1 = require("fetch-socks");
|
|
47
|
+
const node_crypto_1 = tslib_1.__importDefault(require("node:crypto"));
|
|
46
48
|
class OnboardingServiceFactory {
|
|
47
49
|
context;
|
|
48
50
|
cliConfig;
|
|
@@ -119,7 +121,8 @@ class OnboardingServiceFactory {
|
|
|
119
121
|
async getFetchEventHandler(files, customerConfig, documentHandler, cache, cli, browserContext, athenaClient) {
|
|
120
122
|
const configApi = this.getConfigApi(customerConfig.app);
|
|
121
123
|
const serverConfig = await this.getSpeedKitServerConfig(configApi, cli);
|
|
122
|
-
const
|
|
124
|
+
const agent = this.getCrawlerAgent(customerConfig, cli);
|
|
125
|
+
const crawler = new crawler_1.Crawler(cli, agent, serverConfig);
|
|
123
126
|
const parameterQueryBuilder = new parameter_query_builder_1.ParameterQueryBuilder(customerConfig, files.getByName(files_1.INTEGRATION_FILES.CONFIG.SPEED_KIT));
|
|
124
127
|
const DiffService = new diff_1.DiffServiceFactory(new diff_1.DiffContext(this.cliConfig.diffExec, this.cliConfig.diffExecTemplate)).getService();
|
|
125
128
|
const requestDiffService = new request_diff_service_1.RequestDiffService(DiffService, documentHandler);
|
|
@@ -214,5 +217,43 @@ class OnboardingServiceFactory {
|
|
|
214
217
|
ensureHttps(url = "") {
|
|
215
218
|
return url.startsWith("https://") ? url : `https://${url}`;
|
|
216
219
|
}
|
|
220
|
+
getCrawlerAgent(customerConfig, cli) {
|
|
221
|
+
const proxy = [];
|
|
222
|
+
const connect = {
|
|
223
|
+
keepAlive: true,
|
|
224
|
+
};
|
|
225
|
+
const agentOptions = {
|
|
226
|
+
rejectUnauthorized: false,
|
|
227
|
+
secureOptions: node_crypto_1.default.constants.SSL_OP_LEGACY_SERVER_CONNECT,
|
|
228
|
+
};
|
|
229
|
+
const crawlerProxyConfig = this.getCrawlerProxyConfig(customerConfig);
|
|
230
|
+
if (crawlerProxyConfig) {
|
|
231
|
+
cli.writeWarning(`use proxy from chromeFlags for local documenthandler`);
|
|
232
|
+
proxy.push(crawlerProxyConfig);
|
|
233
|
+
}
|
|
234
|
+
return (0, fetch_socks_1.socksDispatcher)(proxy, { ...agentOptions, connect });
|
|
235
|
+
}
|
|
236
|
+
getCrawlerProxyConfig(customerConfig) {
|
|
237
|
+
if (!customerConfig.chromeFlags ||
|
|
238
|
+
customerConfig.chromeFlags.length === 0) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
//"--proxy-server=socks5://ap-northeast-1.proxy.baqend.com:1080"
|
|
242
|
+
const selector = /--proxy-server=socks(4|5):(\/\/[^:]*):(\d+)/is;
|
|
243
|
+
for (const flag of customerConfig.chromeFlags) {
|
|
244
|
+
if (!flag.includes("--proxy-server=socks")) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const [, type, host, port] = flag.match(selector) || [];
|
|
248
|
+
if (!type || !host || !port) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
type: Number(type),
|
|
253
|
+
host,
|
|
254
|
+
port: Number(port),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
217
258
|
}
|
|
218
259
|
exports.OnboardingServiceFactory = OnboardingServiceFactory;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { SpeedKitServerConfig } from "../onboarding-model";
|
|
2
2
|
import { CliService } from "../../cli";
|
|
3
|
+
import { Agent } from "undici";
|
|
3
4
|
export declare class Crawler {
|
|
4
5
|
private cli;
|
|
6
|
+
private agentConfig;
|
|
5
7
|
private speedKitServerConfig?;
|
|
6
|
-
constructor(cli: CliService, speedKitServerConfig?: SpeedKitServerConfig);
|
|
8
|
+
constructor(cli: CliService, agentConfig: Agent, speedKitServerConfig?: SpeedKitServerConfig);
|
|
7
9
|
fetchRemote(originUrl: string, variation: string): Promise<Response>;
|
|
8
10
|
private setDefaultUserAgent;
|
|
9
11
|
private prepareOriginRequest;
|
|
@@ -1,58 +1,62 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Crawler = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
4
|
const onboarding_model_1 = require("../onboarding-model");
|
|
6
5
|
const safe_1 = require("../../../helpers/safe");
|
|
7
|
-
const
|
|
8
|
-
const node_crypto_1 = tslib_1.__importDefault(require("node:crypto"));
|
|
9
|
-
const agent = new node_https_1.Agent({
|
|
10
|
-
rejectUnauthorized: false,
|
|
11
|
-
keepAlive: true,
|
|
12
|
-
secureOptions: node_crypto_1.default.constants.SSL_OP_LEGACY_SERVER_CONNECT,
|
|
13
|
-
});
|
|
6
|
+
const cli_1 = require("../../cli");
|
|
14
7
|
class Crawler {
|
|
15
8
|
cli;
|
|
9
|
+
agentConfig;
|
|
16
10
|
speedKitServerConfig;
|
|
17
|
-
constructor(cli, speedKitServerConfig) {
|
|
11
|
+
constructor(cli, agentConfig, speedKitServerConfig) {
|
|
18
12
|
this.cli = cli;
|
|
13
|
+
this.agentConfig = agentConfig;
|
|
19
14
|
this.speedKitServerConfig = speedKitServerConfig;
|
|
20
15
|
}
|
|
21
16
|
async fetchRemote(originUrl, variation) {
|
|
22
17
|
const userAgent = this.setDefaultUserAgent(variation);
|
|
23
|
-
const headers = {
|
|
18
|
+
const headers = {
|
|
19
|
+
"User-Agent": userAgent,
|
|
20
|
+
};
|
|
24
21
|
const requestInit = {
|
|
25
22
|
...this.prepareOriginRequest(originUrl, variation, {
|
|
26
23
|
headers,
|
|
27
24
|
}),
|
|
28
|
-
agent,
|
|
25
|
+
agent: this.agentConfig,
|
|
29
26
|
};
|
|
27
|
+
this.cli.startAction(`[documentHandler:fetch]: ${originUrl}`);
|
|
30
28
|
const fetchResponse = await (0, safe_1.safe)(fetch(originUrl, requestInit));
|
|
31
29
|
if (fetchResponse.success === true) {
|
|
30
|
+
this.cli.endAction(cli_1.CliActionStatus.COMPLETED);
|
|
32
31
|
return fetchResponse.data;
|
|
33
32
|
}
|
|
33
|
+
this.cli.endAction(cli_1.CliActionStatus.FAILED);
|
|
34
34
|
this.cli.writeError(`error while fetching Asset: ${originUrl}`);
|
|
35
35
|
this.cli.writeError(fetchResponse.error);
|
|
36
36
|
this.cli.writeError(JSON.stringify(fetchResponse.errorObj));
|
|
37
37
|
}
|
|
38
38
|
setDefaultUserAgent(variation) {
|
|
39
|
-
if (
|
|
39
|
+
if (/^mobile$/is.test(variation)) {
|
|
40
40
|
return onboarding_model_1.USER_AGENT.MOBILE;
|
|
41
41
|
}
|
|
42
|
-
if (
|
|
42
|
+
if (/^tablet$/is.test(variation)) {
|
|
43
43
|
return onboarding_model_1.USER_AGENT.TABLET;
|
|
44
44
|
}
|
|
45
|
-
if (variation.includes("tv")) {
|
|
46
|
-
return onboarding_model_1.USER_AGENT.TV;
|
|
47
|
-
}
|
|
48
45
|
return onboarding_model_1.USER_AGENT.DESKTOP;
|
|
49
46
|
}
|
|
50
47
|
prepareOriginRequest(originUrl, variationParameter, init) {
|
|
51
|
-
if (!this.speedKitServerConfig
|
|
48
|
+
if (!this.speedKitServerConfig) {
|
|
49
|
+
return init;
|
|
50
|
+
}
|
|
51
|
+
if (this.speedKitServerConfig.speedKit.variations?.["*"]) {
|
|
52
|
+
const config = this.speedKitServerConfig.speedKit.variations["*"];
|
|
53
|
+
init.headers = { ...init.headers, ...config.headers };
|
|
54
|
+
}
|
|
55
|
+
if (!variationParameter) {
|
|
52
56
|
return init;
|
|
53
57
|
}
|
|
54
58
|
for (const variationKey in this.speedKitServerConfig.speedKit.variations) {
|
|
55
|
-
if (variationParameter === variationKey
|
|
59
|
+
if (variationParameter === variationKey) {
|
|
56
60
|
const variationConfig = this.speedKitServerConfig.speedKit.variations[variationKey];
|
|
57
61
|
init.headers = { ...init.headers, ...variationConfig.headers };
|
|
58
62
|
return init;
|
|
@@ -27,7 +27,7 @@ class VirtualOrestesApp {
|
|
|
27
27
|
const UrlObject = new URL(event.request.url);
|
|
28
28
|
const variation = UrlObject.searchParams.has("bqvariation")
|
|
29
29
|
? UrlObject.searchParams.get("bqvariation").trim()
|
|
30
|
-
: "
|
|
30
|
+
: "default";
|
|
31
31
|
const cachedResponse = this.getCachedResponse(event.request.url);
|
|
32
32
|
if (cachedResponse instanceof baqend_response_1.BaqendResponse) {
|
|
33
33
|
return cachedResponse;
|
|
@@ -35,11 +35,11 @@ class VirtualOrestesApp {
|
|
|
35
35
|
const response = await this.crawler.fetchRemote(originUrl, variation);
|
|
36
36
|
// todo check if we can handle more then htmlResponses
|
|
37
37
|
// only handle html responses
|
|
38
|
-
if (!response
|
|
38
|
+
if (!response?.headers?.get("Content-Type")?.includes("html")) {
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
-
const hasNoStoreFlag = response
|
|
42
|
-
|
|
41
|
+
const hasNoStoreFlag = response?.headers
|
|
42
|
+
?.get("Cache-Control")
|
|
43
43
|
?.includes("no-store");
|
|
44
44
|
const customHeaders = this.prepareCustomHeaders(originUrl, hasNoStoreFlag);
|
|
45
45
|
// CDN Redirect
|
|
@@ -50,7 +50,7 @@ class VirtualOrestesApp {
|
|
|
50
50
|
return this.returnRedirect(customHeaders, response, event);
|
|
51
51
|
}
|
|
52
52
|
const { responseContent, responseEncoding } = await this.getResponseText(response);
|
|
53
|
-
if (!this.isHtmlContentHeader(response
|
|
53
|
+
if (!this.isHtmlContentHeader(response?.headers) ||
|
|
54
54
|
!this.isValidHtmlContent(responseContent)) {
|
|
55
55
|
const customResponse = new baqend_response_1.BaqendResponse(responseContent, `text/html; charset=${responseEncoding}`, customHeaders);
|
|
56
56
|
this.cache.addEntry(event.request.url, customResponse);
|
|
@@ -68,28 +68,28 @@ class VirtualOrestesApp {
|
|
|
68
68
|
if (!Buffer.isBuffer(skResponse.body) && this.customerConfig.forceInstall) {
|
|
69
69
|
skResponse.body = this.rewriteInstallResource(skResponse.body);
|
|
70
70
|
}
|
|
71
|
-
for (const key in skResponse
|
|
71
|
+
for (const key in skResponse?.headers) {
|
|
72
72
|
customHeaders.push({
|
|
73
73
|
name: key,
|
|
74
|
-
value: skResponse
|
|
74
|
+
value: skResponse?.headers[key],
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
const originHeaders = [];
|
|
78
78
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
79
|
-
response
|
|
79
|
+
response?.headers.forEach((value, key) => {
|
|
80
80
|
originHeaders.push({ name: `x-origin-${key}`, value: value });
|
|
81
81
|
});
|
|
82
82
|
customHeaders.push({
|
|
83
83
|
name: "x-sk-detected-encoding",
|
|
84
84
|
value: responseEncoding,
|
|
85
85
|
});
|
|
86
|
-
const baqendResponse = new baqend_response_1.BaqendResponse(skResponse.body, response
|
|
86
|
+
const baqendResponse = new baqend_response_1.BaqendResponse(skResponse.body, response?.headers.get("Content-Type"), [...customHeaders, ...originHeaders]);
|
|
87
87
|
this.cache.addEntry(event.request.url, baqendResponse);
|
|
88
88
|
return baqendResponse;
|
|
89
89
|
}
|
|
90
90
|
async getResponseText(response) {
|
|
91
91
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
92
|
-
const contentType = response
|
|
92
|
+
const contentType = response?.headers.get("content-type") || "";
|
|
93
93
|
const charsetRegex = /charset=([^\s"(),./:;<=>?@[\]]*)/i;
|
|
94
94
|
const encodingFromHeader = contentType && charsetRegex.test(contentType)
|
|
95
95
|
? charsetRegex.exec(contentType)[1]
|
|
@@ -125,7 +125,7 @@ class VirtualOrestesApp {
|
|
|
125
125
|
convertResponseHeadersToOrestesFormat(response) {
|
|
126
126
|
const convertedResponseHeaders = {};
|
|
127
127
|
// eslint-disable-next-line unicorn/no-array-for-each
|
|
128
|
-
response
|
|
128
|
+
response?.headers?.forEach((value, key) => {
|
|
129
129
|
convertedResponseHeaders[key] = value;
|
|
130
130
|
});
|
|
131
131
|
return convertedResponseHeaders;
|
|
@@ -133,7 +133,7 @@ class VirtualOrestesApp {
|
|
|
133
133
|
returnRedirect(customHeaders, response, event) {
|
|
134
134
|
customHeaders.push({
|
|
135
135
|
name: "location",
|
|
136
|
-
value: response
|
|
136
|
+
value: response?.headers.get("location") || "",
|
|
137
137
|
});
|
|
138
138
|
const redirectResponse = new baqend_response_1.BaqendResponse("", null, customHeaders, response.status);
|
|
139
139
|
this.cache.addEntry(event.request.url, redirectResponse);
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speedkit/cli",
|
|
3
3
|
"description": "Speed Kit CLI",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.23.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Baqend.com",
|
|
7
7
|
"email": "info@baqend.com"
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"encoding-japanese": "^2.2.0",
|
|
86
86
|
"esbuild": "^0.20.2",
|
|
87
87
|
"extract-zip": "^2.0.1",
|
|
88
|
+
"fetch-socks": "^1.3.2",
|
|
88
89
|
"fluent-ffmpeg": "^2.1.3",
|
|
89
90
|
"fs-extra": "^11.2.0",
|
|
90
91
|
"handlebars": "^4.7.8",
|