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.
@@ -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
- /** 需要额外写入的 header(不包含 ua) */
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: RequestInfo | URL): Promise<Response>;
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
- return this.fetchHelper(request, 0);
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(request, _count) {
87
+ fetchHelper(url, _count) {
28
88
  if (this.fetchingCount < this.limit) {
29
- return this.createFetchTask(request, _count);
89
+ return this.createFetchTask(url, _count);
30
90
  }
31
91
  else {
32
92
  return new Promise((resolve, reject) => {
33
- this.waitList.push({ request, resolve, reject });
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 controller = new AbortController();
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
- throw e; // 如果不需要重试直接向上级抛出异常
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.request)
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 fs_1 = __importDefault(require("fs"));
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 = fs_1.default.lstatSync(dir);
126
+ const stats = await promises_1.default.lstat(dir);
127
127
  if (stats.isDirectory()) {
128
- await new Promise((resolve, reject) => {
129
- fs_1.default.readdir(dir, (err, files) => {
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 (isNotFound.error(e) && notFoundLevel == CompilationEnv_1.AllowNotFoundEnum.ALLOW_ALL) {
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.statSync(cliConfig.webRoot).isDirectory()) {
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.mkdirSync(path_1.default.join(cliConfig.webRoot, jsonInfo.swppPath), { recursive: true });
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").PathOrFileDescriptor) => Promise<string>>;
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
  /** 解析指定类型的文件内容 */
@@ -54,7 +54,7 @@ function buildCommon() {
54
54
  });
55
55
  }
56
56
  catch (e) {
57
- console.warn('Periodic Sync 注册失败', e);
57
+ console.log('Periodic Sync 注册失败', e);
58
58
  }
59
59
  })
60
60
  .catch(err => console.error('SWPP 注册失败', err));
@@ -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 : new Response(err.toString(), { status: -1 });
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 : new Response(err.toString(), { status: -1 });
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
  })
@@ -1,4 +1,4 @@
1
- import { PathOrFileDescriptor, WriteFileOptions } from 'fs';
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: PathOrFileDescriptor, data: string | NodeJS.ArrayBufferView, optional?: WriteFileOptions): Promise<void>;
68
+ writeFile(path: fs.PathLike, data: string | NodeJS.ArrayBufferView, optional?: WriteFileOptions): Promise<void>;
69
69
  /** 读取一个文件 */
70
- readFileUtf8(path: PathOrFileDescriptor): Promise<string>;
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
  /** 未知分类错误 */
@@ -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 new Promise((resolve, reject) => {
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 new Promise((resolve, reject) => {
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
  /** 未知分类错误 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swpp-backends",
3
- "version": "3.0.0-alpha.430",
3
+ "version": "3.0.0-alpha.441",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
6
6
  "description": "Generate a powerful ServiceWorker for your website.",