swpp-backends 3.0.0-alpha.430 → 3.0.0-alpha.441
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/dist/swpp/NetworkFileHandler.d.ts +13 -2
- package/dist/swpp/NetworkFileHandler.js +126 -25
- package/dist/swpp/ResourcesScanner.js +9 -12
- package/dist/swpp/cli.js +25 -15
- package/dist/swpp/database/CompilationEnv.d.ts +1 -1
- package/dist/swpp/database/CompilationFileParser.js +12 -1
- package/dist/swpp/database/DomCode.js +1 -1
- package/dist/swpp/database/RuntimeDepCode.d.ts +13 -1
- package/dist/swpp/database/RuntimeDepCode.js +30 -7
- package/dist/swpp/untils.d.ts +6 -4
- package/dist/swpp/untils.js +5 -17
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as http from 'node:http';
|
|
1
2
|
export interface NetworkFileHandler {
|
|
2
3
|
/** 最大并发量 */
|
|
3
4
|
limit: number;
|
|
@@ -7,7 +8,9 @@ export interface NetworkFileHandler {
|
|
|
7
8
|
referer: string;
|
|
8
9
|
/** 拉取文件时使用的 ua */
|
|
9
10
|
userAgent: string;
|
|
10
|
-
/**
|
|
11
|
+
/** HTTP 代理 */
|
|
12
|
+
proxy?: http.Agent;
|
|
13
|
+
/** 需要额外写入的 header(不包含 ua 和 referer) */
|
|
11
14
|
headers: {
|
|
12
15
|
[name: string]: string;
|
|
13
16
|
};
|
|
@@ -22,6 +25,12 @@ export interface NetworkFileHandler {
|
|
|
22
25
|
* @param err 失败的原因
|
|
23
26
|
*/
|
|
24
27
|
isRetry(request: RequestInfo | URL, count: number, err: any): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* 获取备用 URL 列表
|
|
30
|
+
* @param url
|
|
31
|
+
* @return 返回的数组中的第一个元素将用于替换原有的 URL
|
|
32
|
+
*/
|
|
33
|
+
getStandbyList(url: string | URL): (string | URL)[];
|
|
25
34
|
}
|
|
26
35
|
/** 支持并发控制的网络文件拉取工具 */
|
|
27
36
|
export declare class FiniteConcurrencyFetcher implements NetworkFileHandler {
|
|
@@ -36,9 +45,11 @@ export declare class FiniteConcurrencyFetcher implements NetworkFileHandler {
|
|
|
36
45
|
retryLimit: number;
|
|
37
46
|
/** 重试次数计数 */
|
|
38
47
|
private retryCount;
|
|
39
|
-
fetch(request:
|
|
48
|
+
fetch(request: string | URL): Promise<Response>;
|
|
40
49
|
private fetchHelper;
|
|
41
50
|
private createFetchTask;
|
|
42
51
|
getUrlContentType(url: string, response?: Response): string;
|
|
43
52
|
isRetry(_request: RequestInfo | URL, count: number, err: any): boolean;
|
|
53
|
+
getStandbyList(url: string | URL): (string | URL)[];
|
|
54
|
+
private request;
|
|
44
55
|
}
|
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.FiniteConcurrencyFetcher = void 0;
|
|
30
|
+
const http = __importStar(require("node:http"));
|
|
31
|
+
const https = __importStar(require("node:https"));
|
|
7
32
|
const path_1 = __importDefault(require("path"));
|
|
8
33
|
const untils_1 = require("./untils");
|
|
9
34
|
/** 支持并发控制的网络文件拉取工具 */
|
|
@@ -21,60 +46,82 @@ class FiniteConcurrencyFetcher {
|
|
|
21
46
|
/** 重试次数计数 */
|
|
22
47
|
this.retryCount = 0;
|
|
23
48
|
}
|
|
24
|
-
fetch(request) {
|
|
25
|
-
|
|
49
|
+
async fetch(request) {
|
|
50
|
+
const fetchBase = async () => {
|
|
51
|
+
const list = this.getStandbyList(request);
|
|
52
|
+
if (!list || list.length === 0) {
|
|
53
|
+
throw new untils_1.RuntimeException(untils_1.exceptionNames.invalidValue, `#getStandByList(${request.toString()}) 返回了空值或空的数组`);
|
|
54
|
+
}
|
|
55
|
+
if (list.length === 1)
|
|
56
|
+
return this.fetchHelper(list[0], 0);
|
|
57
|
+
try {
|
|
58
|
+
return await this.fetchHelper(list[0], 0);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
list.shift();
|
|
62
|
+
try {
|
|
63
|
+
return await Promise.any(list.map(it => this.fetchHelper(it, 0)));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
return await fetchBase();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
return new Response(JSON.stringify({
|
|
75
|
+
type: err.name,
|
|
76
|
+
message: err.message,
|
|
77
|
+
stack: err.stack,
|
|
78
|
+
addition: err
|
|
79
|
+
}), {
|
|
80
|
+
status: 600,
|
|
81
|
+
headers: {
|
|
82
|
+
'Content-Type': 'application/json'
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
26
86
|
}
|
|
27
|
-
fetchHelper(
|
|
87
|
+
fetchHelper(url, _count) {
|
|
28
88
|
if (this.fetchingCount < this.limit) {
|
|
29
|
-
return this.createFetchTask(
|
|
89
|
+
return this.createFetchTask(url, _count);
|
|
30
90
|
}
|
|
31
91
|
else {
|
|
32
92
|
return new Promise((resolve, reject) => {
|
|
33
|
-
this.waitList.push({
|
|
93
|
+
this.waitList.push({ url, resolve, reject });
|
|
34
94
|
});
|
|
35
95
|
}
|
|
36
96
|
}
|
|
37
97
|
async createFetchTask(url, _count = 0) {
|
|
38
98
|
++this.fetchingCount;
|
|
39
|
-
let clearId = undefined;
|
|
40
99
|
try {
|
|
41
|
-
const
|
|
42
|
-
// noinspection JSUnusedAssignment
|
|
43
|
-
clearId = setTimeout(() => {
|
|
44
|
-
++this.retryCount;
|
|
100
|
+
const response = await this.request(url.toString(), () => {
|
|
45
101
|
if (this.retryCount > 10) { // 超时请求数量过多时自动降低并发量
|
|
46
102
|
this.retryCount = 5;
|
|
47
103
|
this.limit = Math.round(this.limit * 2 / 3);
|
|
48
104
|
untils_1.utils.printWarning('FETCHER', `超时请求数量过多,已将阈值自动降低为 ${this.limit}`);
|
|
49
105
|
}
|
|
50
|
-
controller.abort(new untils_1.RuntimeException(untils_1.exceptionNames.timeout, `链接[${url.toString()}]访问超时`));
|
|
51
|
-
}, this.timeout);
|
|
52
|
-
const response = await fetch(url, {
|
|
53
|
-
referrer: this.referer,
|
|
54
|
-
keepalive: true,
|
|
55
|
-
headers: {
|
|
56
|
-
...this.headers,
|
|
57
|
-
'User-Agent': this.userAgent
|
|
58
|
-
},
|
|
59
|
-
signal: controller.signal
|
|
60
106
|
});
|
|
61
|
-
clearTimeout(clearId);
|
|
62
107
|
--this.fetchingCount;
|
|
63
108
|
return response;
|
|
64
109
|
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
clearTimeout(clearId);
|
|
110
|
+
catch (e) {
|
|
67
111
|
--this.fetchingCount;
|
|
112
|
+
// 出现异常时判断是否需要重试
|
|
68
113
|
if (this.isRetry(url, _count, e)) {
|
|
114
|
+
++this.retryCount;
|
|
69
115
|
untils_1.utils.printWarning('FETCHER', `自动重试请求:${url},重试次数:${_count + 1},重试原因:“${e}”`);
|
|
70
116
|
return this.fetchHelper(url, _count + 1);
|
|
71
117
|
}
|
|
72
|
-
|
|
118
|
+
// 如果不需要重试直接向上级抛出异常
|
|
119
|
+
return new Response(null, { status: 600 });
|
|
73
120
|
}
|
|
74
121
|
finally { // 请求结束后触发等待队列中的任务
|
|
75
122
|
if (this.waitList.length !== 0 && this.fetchingCount < this.limit) {
|
|
76
123
|
const item = this.waitList.pop();
|
|
77
|
-
this.createFetchTask(item.
|
|
124
|
+
this.createFetchTask(item.url)
|
|
78
125
|
.then(response => item.resolve(response))
|
|
79
126
|
.catch(err => item.reject(err));
|
|
80
127
|
}
|
|
@@ -101,5 +148,59 @@ class FiniteConcurrencyFetcher {
|
|
|
101
148
|
isRetry(_request, count, err) {
|
|
102
149
|
return count < this.retryLimit && err instanceof untils_1.RuntimeException && err.code === untils_1.exceptionNames.timeout;
|
|
103
150
|
}
|
|
151
|
+
getStandbyList(url) {
|
|
152
|
+
return [url];
|
|
153
|
+
}
|
|
154
|
+
request(url, onTimeout) {
|
|
155
|
+
return new Promise(async (resolve, reject) => {
|
|
156
|
+
let id = undefined;
|
|
157
|
+
const isHttps = url.startsWith('https:');
|
|
158
|
+
const client = isHttps ? https : http;
|
|
159
|
+
const req = client.get(url, {
|
|
160
|
+
headers: {
|
|
161
|
+
...this.headers,
|
|
162
|
+
referer: this.referer,
|
|
163
|
+
"user-agent": this.userAgent
|
|
164
|
+
},
|
|
165
|
+
// @ts-ignore
|
|
166
|
+
agent: this['proxy']
|
|
167
|
+
}, response => {
|
|
168
|
+
if ([301, 302, 307, 308].includes(response.statusCode ?? 0)) {
|
|
169
|
+
const location = response.headers.location;
|
|
170
|
+
if (!location) {
|
|
171
|
+
reject(new Error(`GET ${url} Error: 返回了 ${response.statusCode} 但没有包含 Location 字段`));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.request(location, onTimeout)
|
|
175
|
+
.then(response => resolve(response))
|
|
176
|
+
.catch(err => reject(err));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const bufferArray = [];
|
|
181
|
+
response.on('data', (chunk) => {
|
|
182
|
+
bufferArray.push(chunk);
|
|
183
|
+
});
|
|
184
|
+
response.on('end', () => {
|
|
185
|
+
clearTimeout(id);
|
|
186
|
+
const buffer = Buffer.concat(bufferArray);
|
|
187
|
+
resolve(new Response(buffer, {
|
|
188
|
+
status: response.statusCode,
|
|
189
|
+
headers: response.headers
|
|
190
|
+
}));
|
|
191
|
+
});
|
|
192
|
+
response.on('error', err => {
|
|
193
|
+
reject(err);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
if (this.timeout > 0) {
|
|
198
|
+
id = setTimeout(() => {
|
|
199
|
+
onTimeout?.();
|
|
200
|
+
req.destroy(new untils_1.RuntimeException(untils_1.exceptionNames.timeout, `GET ${url} Timeout`));
|
|
201
|
+
}, this.timeout);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
104
205
|
}
|
|
105
206
|
exports.FiniteConcurrencyFetcher = FiniteConcurrencyFetcher;
|
|
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.FileUpdateTracker = exports.ResourcesScanner = void 0;
|
|
30
30
|
exports.traverseDirectory = traverseDirectory;
|
|
31
|
-
const
|
|
31
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
32
32
|
const crypto = __importStar(require("node:crypto"));
|
|
33
33
|
const path_1 = __importDefault(require("path"));
|
|
34
34
|
const CompilationEnv_1 = require("./database/CompilationEnv");
|
|
@@ -123,17 +123,10 @@ exports.ResourcesScanner = ResourcesScanner;
|
|
|
123
123
|
* @param callback
|
|
124
124
|
*/
|
|
125
125
|
async function traverseDirectory(dir, callback) {
|
|
126
|
-
const stats =
|
|
126
|
+
const stats = await promises_1.default.lstat(dir);
|
|
127
127
|
if (stats.isDirectory()) {
|
|
128
|
-
await
|
|
129
|
-
|
|
130
|
-
if (err)
|
|
131
|
-
reject(err);
|
|
132
|
-
else {
|
|
133
|
-
Promise.all(files.map(it => traverseDirectory(path_1.default.posix.join(dir, it), callback))).then(() => resolve());
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
});
|
|
128
|
+
const files = await promises_1.default.readdir(dir);
|
|
129
|
+
await Promise.all(files.map(it => traverseDirectory(path_1.default.posix.join(dir, it), callback)));
|
|
137
130
|
}
|
|
138
131
|
else {
|
|
139
132
|
await callback(dir);
|
|
@@ -301,11 +294,15 @@ class FileUpdateTracker {
|
|
|
301
294
|
untils_1.utils.printWarning('SCANNER', '拉取 tracker 时服务器返回了 404,如果是第一次携带 swpp v3 构建网站请忽视这条信息');
|
|
302
295
|
return new FileUpdateTracker(compilation);
|
|
303
296
|
}
|
|
297
|
+
if (![200, 301, 302, 307, 308].includes(response.status)) {
|
|
298
|
+
// noinspection ExceptionCaughtLocallyJS
|
|
299
|
+
throw response;
|
|
300
|
+
}
|
|
304
301
|
const text = await response.text();
|
|
305
302
|
return FileUpdateTracker.unJson(compilation, text);
|
|
306
303
|
}
|
|
307
304
|
catch (e) {
|
|
308
|
-
if (
|
|
305
|
+
if (notFoundLevel == CompilationEnv_1.AllowNotFoundEnum.ALLOW_ALL && isNotFound.error(e)) {
|
|
309
306
|
untils_1.utils.printWarning('SCANNER', '拉取 tracker 时 DNS 解析失败,如果是第一次携带 swpp v3 构建网站且网站暂时无法解析请忽视这条信息');
|
|
310
307
|
return new FileUpdateTracker(compilation);
|
|
311
308
|
}
|
package/dist/swpp/cli.js
CHANGED
|
@@ -51,8 +51,8 @@ async function initCommand() {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
/** 检查并初始化 CLI 配置 */
|
|
54
|
-
function checkAndInitConfig(cliConfig) {
|
|
55
|
-
if (!cliConfig.webRoot || !fs_1.default.existsSync(cliConfig.webRoot) || !fs_1.default.
|
|
54
|
+
async function checkAndInitConfig(cliConfig) {
|
|
55
|
+
if (!cliConfig.webRoot || !fs_1.default.existsSync(cliConfig.webRoot) || !(await fs_1.default.promises.stat(cliConfig.webRoot)).isDirectory()) {
|
|
56
56
|
throw new untils_1.RuntimeException(untils_1.exceptionNames.error, 'CLI 配置文件中缺少 webRoot 配置项或传入了一个非文件夹路径', { webRoot: cliConfig.webRoot });
|
|
57
57
|
}
|
|
58
58
|
if (cliConfig.domJsPath && (!cliConfig.domJsPath.startsWith('/') || !cliConfig.domJsPath.endsWith('.js'))) {
|
|
@@ -79,7 +79,7 @@ async function runBuild(cliJsonPath = './swpp.cli.json', context) {
|
|
|
79
79
|
throw new untils_1.RuntimeException(untils_1.exceptionNames.unsupportedFileType, 'CLI 配置文件仅支持 JSON 格式', { yourPath: cliJsonPath });
|
|
80
80
|
}
|
|
81
81
|
const cliConfig = JSON.parse(await untils_1.utils.readFileUtf8(cliJsonPath));
|
|
82
|
-
checkAndInitConfig(cliConfig);
|
|
82
|
+
await checkAndInitConfig(cliConfig);
|
|
83
83
|
// 加载配置项
|
|
84
84
|
const loader = new ConfigLoader_1.ConfigLoader(context);
|
|
85
85
|
for (let item of cliConfig.configFiles) {
|
|
@@ -87,24 +87,34 @@ async function runBuild(cliJsonPath = './swpp.cli.json', context) {
|
|
|
87
87
|
await loader.load(path);
|
|
88
88
|
}
|
|
89
89
|
const { runtime, compilation } = loader.generate();
|
|
90
|
-
//
|
|
90
|
+
// 计算文件目录
|
|
91
91
|
const jsonInfo = compilation.compilationEnv.read('SWPP_JSON_FILE');
|
|
92
|
+
const fileContent = {};
|
|
93
|
+
fileContent[path_1.default.join(cliConfig.webRoot, jsonInfo.swppPath, jsonInfo.trackerPath)] = () => newTracker.json();
|
|
94
|
+
fileContent[path_1.default.join(cliConfig.webRoot, jsonInfo.swppPath, jsonInfo.versionPath)] = () => JSON.stringify(updateJson);
|
|
95
|
+
if (cliConfig.diffJsonPath) {
|
|
96
|
+
fileContent[cliConfig.diffJsonPath] = () => updateJsonBuilder.serialize();
|
|
97
|
+
}
|
|
98
|
+
if (cliConfig.serviceWorker) {
|
|
99
|
+
fileContent[path_1.default.join(cliConfig.webRoot, compilation.compilationEnv.read('SERVICE_WORKER') + '.js')] = () => new SwCompiler_1.SwCompiler().buildSwCode(runtime);
|
|
100
|
+
}
|
|
101
|
+
if (cliConfig.gen_dom) {
|
|
102
|
+
fileContent[path_1.default.join(cliConfig.webRoot, cliConfig.domJsPath ?? '/sw-dom.js')] = () => runtime.domConfig.buildJsSource();
|
|
103
|
+
}
|
|
104
|
+
// 检查文件是否已经存在
|
|
105
|
+
for (let path in fileContent) {
|
|
106
|
+
if (fs_1.default.existsSync(path)) {
|
|
107
|
+
throw new untils_1.RuntimeException(untils_1.exceptionNames.fileDuplicate, `指定文件[${path}]已存在`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// 扫描目录
|
|
92
111
|
const scanner = new ResourcesScanner_1.ResourcesScanner(compilation);
|
|
93
112
|
const newTracker = await scanner.scanLocalFile(cliConfig.webRoot);
|
|
94
113
|
const updateJsonBuilder = await newTracker.diff();
|
|
95
114
|
const updateJson = await updateJsonBuilder.buildJson();
|
|
96
|
-
fs_1.default.
|
|
115
|
+
await fs_1.default.promises.mkdir(path_1.default.join(cliConfig.webRoot, jsonInfo.swppPath), { recursive: true });
|
|
97
116
|
// 生成各项文件
|
|
98
|
-
await Promise.all(
|
|
99
|
-
// 生成 json
|
|
100
|
-
untils_1.utils.writeFile(path_1.default.join(cliConfig.webRoot, jsonInfo.swppPath, jsonInfo.trackerPath), newTracker.json()),
|
|
101
|
-
untils_1.utils.writeFile(path_1.default.join(cliConfig.webRoot, jsonInfo.swppPath, jsonInfo.versionPath), JSON.stringify(updateJson)),
|
|
102
|
-
cliConfig.diffJsonPath ? untils_1.utils.writeFile(cliConfig.diffJsonPath, updateJsonBuilder.serialize()) : null,
|
|
103
|
-
// 生成 sw js
|
|
104
|
-
cliConfig.serviceWorker ? untils_1.utils.writeFile(path_1.default.join(cliConfig.webRoot, compilation.compilationEnv.read('SERVICE_WORKER') + '.js'), new SwCompiler_1.SwCompiler().buildSwCode(runtime)) : null,
|
|
105
|
-
// 生成 dom js
|
|
106
|
-
untils_1.utils.writeFile(path_1.default.join(cliConfig.webRoot, cliConfig.domJsPath ?? '/sw-dom.js'), runtime.domConfig.buildJsSource())
|
|
107
|
-
]);
|
|
117
|
+
await Promise.all(Object.values(untils_1.utils.objMap(fileContent, (value, key) => untils_1.utils.writeFile(key, value()))));
|
|
108
118
|
if (!cliConfig.auto_register && !cliConfig.gen_dom)
|
|
109
119
|
return;
|
|
110
120
|
const regexes = cliConfig.excludes?.map?.(it => new RegExp(it)) ?? [];
|
|
@@ -49,7 +49,7 @@ declare function buildCommon(_env: any): {
|
|
|
49
49
|
/**
|
|
50
50
|
* 读取一个本地文件
|
|
51
51
|
*/
|
|
52
|
-
readonly readLocalFile: import("./KeyValueDatabase").DatabaseValue<(path: import("fs").
|
|
52
|
+
readonly readLocalFile: import("./KeyValueDatabase").DatabaseValue<(path: import("fs").PathLike) => Promise<string>>;
|
|
53
53
|
/**
|
|
54
54
|
* 拉取网络文件
|
|
55
55
|
*/
|
|
@@ -102,7 +102,18 @@ class CompilationFileParser extends KeyValueDatabase_1.KeyValueDatabase {
|
|
|
102
102
|
.then(response => this.parserNetworkFile(response, isCached ? content => {
|
|
103
103
|
mark = untils_1.utils.calcHash(content);
|
|
104
104
|
} : undefined))
|
|
105
|
-
.then(urls => urls.forEach(it => urls.add(it)))
|
|
105
|
+
.then(urls => urls.forEach(it => urls.add(it)))
|
|
106
|
+
.catch(err => new Response(JSON.stringify({
|
|
107
|
+
type: err.type,
|
|
108
|
+
message: err.message,
|
|
109
|
+
stack: err.stack,
|
|
110
|
+
addition: err
|
|
111
|
+
}), {
|
|
112
|
+
status: 600,
|
|
113
|
+
headers: {
|
|
114
|
+
'Content-Type': 'application/json'
|
|
115
|
+
}
|
|
116
|
+
}));
|
|
106
117
|
return { file: url, mark, urls };
|
|
107
118
|
}
|
|
108
119
|
/** 解析指定类型的文件内容 */
|
|
@@ -53,6 +53,10 @@ declare function buildCommon(): {
|
|
|
53
53
|
readonly isFetchSuccessful: {
|
|
54
54
|
readonly default: (response: Response) => boolean;
|
|
55
55
|
};
|
|
56
|
+
/** 将 error 转换为一个 600 Response */
|
|
57
|
+
readonly transferError2Response: {
|
|
58
|
+
readonly default: (err: Error) => Response;
|
|
59
|
+
};
|
|
56
60
|
/** 拉取一个文件 */
|
|
57
61
|
readonly fetchWrapper: {
|
|
58
62
|
readonly default: (request: Request, banCache: boolean, cors: boolean, optional?: RequestInit) => Promise<Response>;
|
|
@@ -82,7 +86,15 @@ declare function buildCommon(): {
|
|
|
82
86
|
l: () => Request[];
|
|
83
87
|
}, optional?: RequestInit) => Promise<Response>;
|
|
84
88
|
};
|
|
85
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* 拉取文件。
|
|
91
|
+
*
|
|
92
|
+
* 该方法不得抛出任何形式的异常,当遇到异常时,应当封装为 response 返回,状态码设置为 `6xx`
|
|
93
|
+
*
|
|
94
|
+
* @param {RequestInfo | URL} request 请求头或 URL
|
|
95
|
+
* @param {?RequestInit} optional 配置项
|
|
96
|
+
* @return {Response}
|
|
97
|
+
*/
|
|
86
98
|
readonly fetchFile: {
|
|
87
99
|
readonly default: import("../config/SpecialConfig").LazyInitConfig<(requestOrUrl: RequestInfo | URL, optional?: RequestInit) => Promise<Response>>;
|
|
88
100
|
};
|
|
@@ -17,6 +17,7 @@ let getStandbyRequests;
|
|
|
17
17
|
let isFetchSuccessful;
|
|
18
18
|
let fetchStandby;
|
|
19
19
|
let fetchFastest;
|
|
20
|
+
let transferError2Response;
|
|
20
21
|
/** 运行时依赖代码 */
|
|
21
22
|
class RuntimeDepCode extends RuntimeKeyValueDatabase_1.RuntimeKeyValueDatabase {
|
|
22
23
|
constructor() {
|
|
@@ -37,7 +38,7 @@ const fetchFastestAndStandbyRequests = (requestOrUrl, optional) => {
|
|
|
37
38
|
const fastestList = getFastestRequests(request);
|
|
38
39
|
if (fastestList)
|
|
39
40
|
return fetchFastest(fastestList, optional);
|
|
40
|
-
return fetchWrapper(request, true, isCors(request), optional);
|
|
41
|
+
return fetchWrapper(request, true, isCors(request), optional).catch(transferError2Response);
|
|
41
42
|
};
|
|
42
43
|
const fetchFastestRequests = (requestOrUrl, optional) => {
|
|
43
44
|
// @ts-ignore
|
|
@@ -45,7 +46,7 @@ const fetchFastestRequests = (requestOrUrl, optional) => {
|
|
|
45
46
|
const fastestList = getFastestRequests(request);
|
|
46
47
|
if (fastestList)
|
|
47
48
|
return fetchFastest(fastestList, optional);
|
|
48
|
-
return fetchWrapper(request, true, isCors(request), optional);
|
|
49
|
+
return fetchWrapper(request, true, isCors(request), optional).catch(transferError2Response);
|
|
49
50
|
};
|
|
50
51
|
const fetchStandbyRequests = (requestOrUrl, optional) => {
|
|
51
52
|
// @ts-ignore
|
|
@@ -53,7 +54,7 @@ const fetchStandbyRequests = (requestOrUrl, optional) => {
|
|
|
53
54
|
const standbyList = getStandbyRequests(request);
|
|
54
55
|
if (standbyList)
|
|
55
56
|
return fetchStandby(request, standbyList, optional);
|
|
56
|
-
return fetchWrapper(request, true, isCors(request), optional);
|
|
57
|
+
return fetchWrapper(request, true, isCors(request), optional).catch(transferError2Response);
|
|
57
58
|
};
|
|
58
59
|
function buildCommon() {
|
|
59
60
|
return {
|
|
@@ -141,6 +142,20 @@ function buildCommon() {
|
|
|
141
142
|
isFetchSuccessful: {
|
|
142
143
|
default: (response) => [200, 301, 302, 307, 308].includes(response.status)
|
|
143
144
|
},
|
|
145
|
+
/** 将 error 转换为一个 600 Response */
|
|
146
|
+
transferError2Response: {
|
|
147
|
+
default: (err) => new Response(JSON.stringify({
|
|
148
|
+
type: err.name,
|
|
149
|
+
message: err.message,
|
|
150
|
+
stack: err.stack,
|
|
151
|
+
addition: err
|
|
152
|
+
}), {
|
|
153
|
+
status: 600,
|
|
154
|
+
headers: {
|
|
155
|
+
'Content-Type': 'application/json'
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
},
|
|
144
159
|
/** 拉取一个文件 */
|
|
145
160
|
fetchWrapper: {
|
|
146
161
|
default: (request, banCache, cors, optional) => {
|
|
@@ -205,7 +220,7 @@ function buildCommon() {
|
|
|
205
220
|
}
|
|
206
221
|
catch (err) {
|
|
207
222
|
const value = err.errors[0];
|
|
208
|
-
return value.body ? value :
|
|
223
|
+
return value.body ? value : transferError2Response(err);
|
|
209
224
|
}
|
|
210
225
|
}
|
|
211
226
|
},
|
|
@@ -255,11 +270,19 @@ function buildCommon() {
|
|
|
255
270
|
}
|
|
256
271
|
catch (err) {
|
|
257
272
|
const value = err.errors[0];
|
|
258
|
-
return value.body ? value :
|
|
273
|
+
return value.body ? value : transferError2Response(err);
|
|
259
274
|
}
|
|
260
275
|
}
|
|
261
276
|
},
|
|
262
|
-
/**
|
|
277
|
+
/**
|
|
278
|
+
* 拉取文件。
|
|
279
|
+
*
|
|
280
|
+
* 该方法不得抛出任何形式的异常,当遇到异常时,应当封装为 response 返回,状态码设置为 `6xx`
|
|
281
|
+
*
|
|
282
|
+
* @param {RequestInfo | URL} request 请求头或 URL
|
|
283
|
+
* @param {?RequestInit} optional 配置项
|
|
284
|
+
* @return {Response}
|
|
285
|
+
*/
|
|
263
286
|
fetchFile: {
|
|
264
287
|
default: (0, ConfigCluster_1.defineLazyInitConfig)((runtime) => {
|
|
265
288
|
const runtimeDep = runtime.runtimeDep;
|
|
@@ -279,7 +302,7 @@ function buildCommon() {
|
|
|
279
302
|
// @ts-ignore
|
|
280
303
|
if (!request.url)
|
|
281
304
|
request = new Request(request);
|
|
282
|
-
return fetchWrapper(request, true, true, optional);
|
|
305
|
+
return fetchWrapper(request, true, true, optional).catch(transferError2Response);
|
|
283
306
|
};
|
|
284
307
|
}
|
|
285
308
|
})
|
package/dist/swpp/untils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import fs, { WriteFileOptions } from 'fs';
|
|
2
2
|
import * as crypto from 'node:crypto';
|
|
3
3
|
export type ValuesOf<T> = T[keyof T];
|
|
4
4
|
export declare const utils: {
|
|
@@ -50,7 +50,7 @@ export declare const utils: {
|
|
|
50
50
|
* @param obj
|
|
51
51
|
* @param transfer
|
|
52
52
|
*/
|
|
53
|
-
objMap<T, R>(obj: Readonly<Record<string, T>>, transfer: (item: T) => R): {
|
|
53
|
+
objMap<T, R>(obj: Readonly<Record<string, T>>, transfer: (item: T, key: string) => R): {
|
|
54
54
|
[key: string]: R;
|
|
55
55
|
};
|
|
56
56
|
/**
|
|
@@ -65,9 +65,9 @@ export declare const utils: {
|
|
|
65
65
|
*/
|
|
66
66
|
findSecondLastIndex(str: string, searchString: string, position?: number): number;
|
|
67
67
|
/** 写入一个文件 */
|
|
68
|
-
writeFile(path:
|
|
68
|
+
writeFile(path: fs.PathLike, data: string | NodeJS.ArrayBufferView, optional?: WriteFileOptions): Promise<void>;
|
|
69
69
|
/** 读取一个文件 */
|
|
70
|
-
readFileUtf8(path:
|
|
70
|
+
readFileUtf8(path: fs.PathLike): Promise<string>;
|
|
71
71
|
};
|
|
72
72
|
export declare const exceptionNames: {
|
|
73
73
|
/** 循环依赖 */
|
|
@@ -94,6 +94,8 @@ export declare const exceptionNames: {
|
|
|
94
94
|
readonly configBuilt: "config_built";
|
|
95
95
|
/** 404 错误 */
|
|
96
96
|
readonly notFound: "not_found";
|
|
97
|
+
/** 文件或目录已存在 */
|
|
98
|
+
readonly fileDuplicate: "file_duplicate";
|
|
97
99
|
/** 超时 */
|
|
98
100
|
readonly timeout: "timeout";
|
|
99
101
|
/** 未知分类错误 */
|
package/dist/swpp/untils.js
CHANGED
|
@@ -190,7 +190,7 @@ exports.utils = {
|
|
|
190
190
|
const result = {};
|
|
191
191
|
for (let key in obj) {
|
|
192
192
|
const value = obj[key];
|
|
193
|
-
result[key] = transfer(value);
|
|
193
|
+
result[key] = transfer(value, key);
|
|
194
194
|
}
|
|
195
195
|
return result;
|
|
196
196
|
},
|
|
@@ -218,25 +218,11 @@ exports.utils = {
|
|
|
218
218
|
},
|
|
219
219
|
/** 写入一个文件 */
|
|
220
220
|
writeFile(path, data, optional = 'utf-8') {
|
|
221
|
-
return
|
|
222
|
-
fs_1.default.writeFile(path, data, optional, err => {
|
|
223
|
-
if (err)
|
|
224
|
-
reject(err);
|
|
225
|
-
else
|
|
226
|
-
resolve();
|
|
227
|
-
});
|
|
228
|
-
});
|
|
221
|
+
return fs_1.default.promises.writeFile(path, data, optional);
|
|
229
222
|
},
|
|
230
223
|
/** 读取一个文件 */
|
|
231
224
|
readFileUtf8(path) {
|
|
232
|
-
return
|
|
233
|
-
fs_1.default.readFile(path, 'utf-8', (err, data) => {
|
|
234
|
-
if (err)
|
|
235
|
-
reject(err);
|
|
236
|
-
else
|
|
237
|
-
resolve(data);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
225
|
+
return fs_1.default.promises.readFile(path, 'utf-8');
|
|
240
226
|
}
|
|
241
227
|
};
|
|
242
228
|
exports.exceptionNames = {
|
|
@@ -264,6 +250,8 @@ exports.exceptionNames = {
|
|
|
264
250
|
configBuilt: 'config_built',
|
|
265
251
|
/** 404 错误 */
|
|
266
252
|
notFound: 'not_found',
|
|
253
|
+
/** 文件或目录已存在 */
|
|
254
|
+
fileDuplicate: 'file_duplicate',
|
|
267
255
|
/** 超时 */
|
|
268
256
|
timeout: 'timeout',
|
|
269
257
|
/** 未知分类错误 */
|