@e-mc/request 0.8.6 → 0.9.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/LICENSE CHANGED
@@ -1,11 +1,11 @@
1
- Copyright 2024 An Pham
2
-
3
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
-
5
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
-
7
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
-
9
- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
-
1
+ Copyright 2024 An Pham
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
+
5
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6
+
7
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+
9
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
+
11
11
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @e-mc/request
2
2
 
3
- * NodeJS 14
3
+ * NodeJS 14/16
4
4
  * ES2020
5
5
 
6
6
  ## General Usage
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## Interface
11
11
 
12
- - https://www.unpkg.com/@e-mc/types@0.8.6/lib/index.d.ts
12
+ * [View Source](https://www.unpkg.com/@e-mc/types@0.9.0/lib/index.d.ts)
13
13
 
14
14
  ```typescript
15
15
  import type { IModule, ModuleConstructor } from "./index";
@@ -32,13 +32,13 @@ interface IRequest extends IModule {
32
32
  init(config?: RequestInit): this;
33
33
  apply(options: ApplyOptions): this;
34
34
  addDns(hostname: string, address: string, timeout: number): void;
35
- addDns(hostname: string, address: string, family?: number | string, timeout?: number): void;
35
+ addDns(hostname: string, address: string, family?: string, timeout?: number): void;
36
36
  lookupDns(hostname: string): LookupFunction;
37
37
  proxyOf(uri: string, localhost?: boolean): ProxySettings | undefined;
38
38
  statusOn(name: number | number[], callback: StatusOnCallback): void;
39
- statusOn(name: number | number[], patternUrl: string, callback: StatusOnCallback): void;
39
+ statusOn(name: number | number[], globUrl: string, callback: StatusOnCallback): void;
40
40
  headersOn(name: string | string[], callback: HeadersOnCallback): void;
41
- headersOn(name: string | string[], patternUrl: string, callback: HeadersOnCallback): void;
41
+ headersOn(name: string | string[], globUrl: string, callback: HeadersOnCallback): void;
42
42
  headersOf(uri: string): OutgoingHttpHeaders | undefined;
43
43
  aria2c(uri: string | URL, pathname: string): Promise<string[]>;
44
44
  aria2c(uri: string | URL, options?: Aria2Options): Promise<string[]>;
@@ -80,11 +80,148 @@ interface RequestConstructor extends ModuleConstructor {
80
80
  }
81
81
  ```
82
82
 
83
+ ## Settings
84
+
85
+ ```typescript
86
+ import type { PermittedDirectories } from "./core";
87
+ import type { SecureConfig } from "./http";
88
+ import type { PurgeComponent } from "./settings";
89
+
90
+ import type { LookupAddress } from "dns";
91
+ import type { OutgoingHttpHeaders } from "http";
92
+
93
+ interface RequestModule {
94
+ handler: "@e-mc/request";
95
+ timeout?: number | string;
96
+ read_timeout?: number | string;
97
+ agent?: {
98
+ keep_alive?: boolean;
99
+ timeout?: number | string;
100
+ };
101
+ connect?: {
102
+ timeout?: number | string;
103
+ retry_wait?: number | string;
104
+ retry_after?: number | string;
105
+ retry_limit?: number;
106
+ redirect_limit?: number;
107
+ };
108
+ dns?: {
109
+ family?: number;
110
+ expires?: number | string;
111
+ resolve?: Record<string, Partial<LookupAddress>>;
112
+ };
113
+ use?: {
114
+ http_version?: 1 | 2;
115
+ accept_encoding?: boolean;
116
+ };
117
+ proxy?: {
118
+ address?: string;
119
+ port?: number;
120
+ username?: string;
121
+ password?: string;
122
+ include?: string[];
123
+ exclude?: string[];
124
+ keep_alive?: boolean;
125
+ };
126
+ headers: Record<string, OutgoingHttpHeaders>;
127
+ certs?: Record<string, SecureConfig<string | string[]>>;
128
+ localhost?: string[];
129
+ protocol?: {
130
+ "http/1.1"?: string[];
131
+ h2c?: string[];
132
+ h2?: string[];
133
+ };
134
+ post_limit?: number | string;
135
+ settings?: {
136
+ broadcast_id?: string | string[];
137
+ time_format?: "readable" | "relative" | "none";
138
+ purge?: PurgeComponent;
139
+ }
140
+ }
141
+
142
+ interface DownloadModule {
143
+ expires?: number | string;
144
+ aria2?: {
145
+ bin?: string | false;
146
+ exec?: {
147
+ uid?: number;
148
+ gid?: number;
149
+ };
150
+ update_status?: number | { interval?: number; broadcast_only?: boolean };
151
+ max_concurrent_downloads?: number;
152
+ max_connection_per_server?: number;
153
+ bt_stop_timeout?: number;
154
+ bt_tracker_connect_timeout?: number;
155
+ bt_tracker_timeout?: number;
156
+ min_split_size?: string;
157
+ disk_cache?: number | string;
158
+ lowest_speed_limit?: number | string;
159
+ always_resume?: boolean;
160
+ file_allocation?: "none" | "prealloc" | "trunc" | "falloc";
161
+ conf_path?: string;
162
+ };
163
+ }
164
+ ```
165
+
166
+ ### Example usage
167
+
168
+ ```javascript
169
+ const Request = require("@e-mc/request");
170
+
171
+ const instance = new Request({
172
+ read_timeout: 30,
173
+ connect: {
174
+ timeout: 20, // Seconds
175
+ retry_wait: 1,
176
+ retry_after: 30,
177
+ retry_limit: 3, // Max attempts
178
+ redirect_limit: 10
179
+ },
180
+ use: {
181
+ http_version: 2,
182
+ accept_encoding: true
183
+ },
184
+ dns: {
185
+ family: 4 // ipVersion
186
+ },
187
+ agent: { keep_alive: true }
188
+ });
189
+ request.init({ ipVersion: 6 });
190
+
191
+ const options = {
192
+ format: "yaml",
193
+ httpVersion: 1,
194
+ silent: true,
195
+ headers: { "x-goog-user-project": "project-1" }
196
+ };
197
+ instance.get("http://hostname/path/config.yml", options).then(data => {
198
+ console.log(data.property);
199
+ });
200
+ ```
201
+
202
+ ## NodeJS 14 LTS
203
+
204
+ Any optional fail safe dependencies were removed as of `E-mc 0.9`. The code itself will still be *ES2020* and will continue to work equivalently when self-installing these dependencies:
205
+
206
+ ### Under 15.4 + 16.0
207
+
208
+ ```sh
209
+ npm i abort-controller event-target-shim
210
+ ```
211
+
212
+ ### Under 14.17 + 15.6
213
+
214
+ ```sh
215
+ npm i uuid
216
+ ```
217
+
83
218
  ## References
84
219
 
85
- - https://www.unpkg.com/@e-mc/types@0.8.6/lib/http.d.ts
86
- - https://www.unpkg.com/@e-mc/types@0.8.6/lib/request.d.ts
87
- - https://www.unpkg.com/@e-mc/types@0.8.6/lib/settings.d.ts
220
+ - https://www.unpkg.com/@e-mc/types@0.9.0/lib/http.d.ts
221
+ - https://www.unpkg.com/@e-mc/types@0.9.0/lib/request.d.ts
222
+ - https://www.unpkg.com/@e-mc/types@0.9.0/lib/settings.d.ts
223
+
224
+ * https://www.npmjs.com/package/@types/node
88
225
 
89
226
  ## LICENSE
90
227
 
@@ -1,5 +1,5 @@
1
- import type { HttpHostConstructor } from '../../../types/lib/request';
2
-
3
- declare const HttpHost: HttpHostConstructor;
4
-
1
+ import type { HttpHostConstructor } from '../../../types/lib/request';
2
+
3
+ declare const HttpHost: HttpHostConstructor;
4
+
5
5
  export = HttpHost;
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  var _a, _b, _c, _d;
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
3
  const tls = require("tls");
5
- const types_1 = require("@e-mc/types");
6
4
  const kProtocol = Symbol('protocol');
7
5
  const kSecure = Symbol('secure');
8
6
  const kHostname = Symbol('hostname');
@@ -27,7 +25,7 @@ const HOST_ALPN_H2 = [];
27
25
  })();
28
26
  class HttpHost {
29
27
  static normalizeOrigin(value) {
30
- return value.replace(/\/+$/, '') + (!/:\d+$/.test(value) ? ':' + (value.startsWith('https') ? '443' : '80') : '');
28
+ return (value = value.trim()).replace(/\/+$/, '') + (!/:\d+$/.test(value) ? ':' + (value.startsWith('https') ? '443' : '80') : '');
31
29
  }
32
30
  static formatBasicAuth(url) {
33
31
  return url.username ? decodeURIComponent(url.username) + (url.password ? ':' + decodeURIComponent(url.password) : '') : '';
@@ -40,19 +38,19 @@ class HttpHost {
40
38
  }
41
39
  static defineLocalHost(value) {
42
40
  HOST_LOCAL.clear();
43
- value.forEach(address => (0, types_1.isString)(address) && HOST_LOCAL.add(address.trim()));
41
+ value.forEach(address => HOST_LOCAL.add(address));
44
42
  }
45
43
  static defineProtocolNegotiation(value) {
46
44
  const { h2c, h2 } = value;
47
45
  const http11 = value['http/1.1'];
48
46
  if (Array.isArray(http11)) {
49
- HOST_HTTP_1_1.push(...http11.map(address => this.normalizeOrigin(address.trim())));
47
+ HOST_HTTP_1_1.push(...http11.map(address => this.normalizeOrigin(address)));
50
48
  }
51
49
  if (Array.isArray(h2c)) {
52
- HOST_ALPN_H2C.push(...h2c.map(address => this.normalizeOrigin(address.trim())));
50
+ HOST_ALPN_H2C.push(...h2c.map(address => this.normalizeOrigin(address)));
53
51
  }
54
52
  if (Array.isArray(h2)) {
55
- HOST_ALPN_H2.push(...h2.map(address => this.normalizeOrigin(address.trim())));
53
+ HOST_ALPN_H2.push(...h2.map(address => this.normalizeOrigin(address)));
56
54
  }
57
55
  }
58
56
  constructor(url, httpVersion = 1) {
@@ -173,13 +171,11 @@ class HttpHost {
173
171
  }
174
172
  return false;
175
173
  };
176
- const pattern = new RegExp(`h${i + 1}(?:-\\d+)?="([^:]*):(\\d+)"([^,]*)`, 'g');
177
174
  const addresses = [];
178
175
  const time = Date.now();
179
176
  const hostname = this[kHostname];
180
177
  const excluded = this[kAltSvcError];
181
- let match;
182
- while (match = pattern.exec(altSvc)) {
178
+ for (const match of altSvc.matchAll(new RegExp(`h${i + 1}(?:-\\d+)?="([^:]*):(\\d+)"([^,]*)`, 'g'))) {
183
179
  const port = match[2];
184
180
  if (!match[1] && port === this.port) {
185
181
  increment(2);
@@ -327,9 +323,5 @@ class HttpHost {
327
323
  }
328
324
  }
329
325
  _a = kVersionData, _b = kAltSvc, _c = kAltSvcQueue, _d = kAltSvcError;
330
- exports.default = HttpHost;
331
326
 
332
- if (exports.default) {
333
- module.exports = exports.default;
334
- module.exports.default = exports.default;
335
- }
327
+ module.exports = HttpHost;
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { RequestConstructor } from '../types/lib';
2
-
3
- declare const Request: RequestConstructor;
4
-
1
+ import type { RequestConstructor } from '../types/lib';
2
+
3
+ declare const Request: RequestConstructor;
4
+
5
5
  export = Request;
package/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
3
  const path = require("path");
5
4
  const fs = require("fs");
6
5
  const child_process = require("child_process");
@@ -16,7 +15,6 @@ const combined = require("combined-stream");
16
15
  const pm = require("picomatch");
17
16
  const yaml = require("js-yaml");
18
17
  const which = require("which");
19
- const lib_v4_1 = require("@e-mc/module/lib-v4");
20
18
  const types_1 = require("@e-mc/types");
21
19
  const module_1 = require("@e-mc/module");
22
20
  const host_1 = require("@e-mc/request/http/host");
@@ -36,8 +34,8 @@ const kConnectHttp = Symbol('connectHttp');
36
34
  const kStatusOn = Symbol('statusOn');
37
35
  const kHeadersOn = Symbol('headersOn');
38
36
  const PLATFORM_WIN32 = process.platform === 'win32';
39
- const SUPPORT_NODEJS20 = module_1.default.supported(20);
40
- const SUPPORT_ABORTSIGNAL = module_1.default.supported(15, 3) || module_1.default.supported(14, 17, 0, true);
37
+ const SUPPORT_NODEJS20 = module_1.supported(20);
38
+ const SUPPORT_ABORTSIGNAL = module_1.supported(15, 3) || module_1.supported(14, 17, 0, true);
41
39
  const HTTP = {
42
40
  HOST: {},
43
41
  HEADERS: {},
@@ -139,10 +137,10 @@ function getProxySettings(request, agentTimeout) {
139
137
  const proxy = request.proxy;
140
138
  if (proxy?.address && proxy.port) {
141
139
  const port = (0, util_1.asInt)(proxy.port);
142
- const address = (!module_1.default.isURL(proxy.address) ? port === 80 ? 'http://' : 'https://' : '') + proxy.address;
140
+ const address = (!module_1.isURL(proxy.address) ? port === 80 ? 'http://' : 'https://' : '') + proxy.address;
143
141
  try {
144
142
  let host = new URL(address + ':' + port), include, exclude;
145
- if ((0, types_1.isString)(proxy.username)) {
143
+ if (proxy.username) {
146
144
  host = new URL(host.protocol + '//' + (0, util_1.getBasicAuth)(proxy.username, proxy.password) + host.host);
147
145
  }
148
146
  if ((0, types_1.isArray)(proxy.include)) {
@@ -199,7 +197,7 @@ function validateCerts(certs) {
199
197
  const file = {};
200
198
  const checkFile = (values) => {
201
199
  for (let pathname of values) {
202
- if (module_1.default.isPath(pathname = path.resolve(pathname))) {
200
+ if (module_1.isPath(pathname = path.resolve(pathname))) {
203
201
  return pathname;
204
202
  }
205
203
  }
@@ -270,7 +268,7 @@ function abortHeaders(href, request, options) {
270
268
  }
271
269
  request.destroy(reason);
272
270
  }
273
- class Request extends module_1.default {
271
+ class Request extends module_1 {
274
272
  static async purgeMemory(percent = 1, limit = 0, parent) {
275
273
  if (percent >= 1) {
276
274
  resetHttpHost();
@@ -414,7 +412,7 @@ class Request extends module_1.default {
414
412
  }
415
413
  LOG_HTTP = this.hasLogType(1024);
416
414
  LOG_TIMEPROCESS = this.hasLogType(256);
417
- LOG_STDOUT = module_1.default.hasLogType(32768);
415
+ LOG_STDOUT = module_1.hasLogType(32768);
418
416
  return true;
419
417
  }
420
418
  static readCACert(value, cache) {
@@ -433,7 +431,7 @@ class Request extends module_1.default {
433
431
  if (this.isURL(value)) {
434
432
  return value;
435
433
  }
436
- const auth = host_1.default.formatBasicAuth(url);
434
+ const auth = host_1.formatBasicAuth(url);
437
435
  return url.protocol + '//' + (auth && (auth + '@')) + url.hostname + (url.port ? ':' + url.port : '') + (value.startsWith('/') ? '' : '/') + value;
438
436
  }
439
437
  static fromStatusCode(value) {
@@ -745,19 +743,19 @@ class Request extends module_1.default {
745
743
  const width = count.toString().length;
746
744
  output.forEach(item => {
747
745
  const [title, origin, downloads, messages] = item;
748
- const options = { ...title === 'HTTP1' ? module_1.default.LOG_STYLE_NOTICE : module_1.default.LOG_STYLE_INFO };
746
+ const options = { ...title === 'HTTP1' ? module_1.LOG_STYLE_NOTICE : module_1.LOG_STYLE_INFO };
749
747
  if (messages.length === 1) {
750
748
  const message = messages[0];
751
749
  message[1] = title;
752
750
  message[2] = [origin + message[2][0], message[2][1]];
753
751
  message[4] = Object.assign(message[4], options);
754
- module_1.default.formatMessage(...message);
752
+ module_1.formatMessage(...message);
755
753
  }
756
754
  else {
757
755
  this.formatMessage(1024, title, [origin, 'downloads: ' + downloads.toString().padStart(width)], '', options);
758
756
  messages.forEach(args => {
759
757
  args[4].titleIndent = true;
760
- module_1.default.formatMessage(...args);
758
+ module_1.formatMessage(...args);
761
759
  });
762
760
  }
763
761
  });
@@ -784,7 +782,7 @@ class Request extends module_1.default {
784
782
  }
785
783
  init(config) {
786
784
  if (config) {
787
- const { headers, httpVersion, ipVersion, requestTimeout, readTimeout = requestTimeout } = config;
785
+ const { headers, httpVersion, ipVersion, readTimeout } = config;
788
786
  if ((0, types_1.isObject)(headers)) {
789
787
  setOutgoingHeaders(this[kHeaders] || (this[kHeaders] = {}), headers);
790
788
  }
@@ -819,7 +817,7 @@ class Request extends module_1.default {
819
817
  this._config.retryWait = Math.min(retryWait, 600 * 1000);
820
818
  }
821
819
  if (retryAfter >= 0) {
822
- this._config.retryAfter = Math.min(retryAfter, module_1.default.MAX_TIMEOUT);
820
+ this._config.retryAfter = Math.min(retryAfter, module_1.MAX_TIMEOUT);
823
821
  }
824
822
  if (retryLimit >= 0) {
825
823
  this._config.retryLimit = retryLimit;
@@ -995,7 +993,7 @@ class Request extends module_1.default {
995
993
  if (!ARIA2.BIN) {
996
994
  return Promise.reject((0, types_1.errorMessage)("aria2", "Binary not found"));
997
995
  }
998
- if (typeof uri === 'string' && module_1.default.isURL(uri)) {
996
+ if (typeof uri === 'string' && module_1.isURL(uri)) {
999
997
  try {
1000
998
  uri = new URL(uri);
1001
999
  }
@@ -1014,7 +1012,7 @@ class Request extends module_1.default {
1014
1012
  let next = false;
1015
1013
  binOpts = binOpts.filter(opt => !((0, types_1.isString)(opt) && /^-[a-z][\S\s]*$/i.test(opt.trim()))).map((opt) => {
1016
1014
  if (next) {
1017
- if (!module_1.default.asString(opt).startsWith('--')) {
1015
+ if (!module_1.asString(opt).startsWith('--')) {
1018
1016
  return [];
1019
1017
  }
1020
1018
  next = false;
@@ -1036,12 +1034,12 @@ class Request extends module_1.default {
1036
1034
  }
1037
1035
  break;
1038
1036
  default:
1039
- return match[3] ? [match[1], module_1.default.sanitizeArgs(match[3])] : [match[1]];
1037
+ return match[3] ? [match[1], module_1.sanitizeArgs(match[3])] : [match[1]];
1040
1038
  }
1041
1039
  }
1042
1040
  }
1043
1041
  else if (value) {
1044
- return [module_1.default.sanitizeArgs(value)];
1042
+ return [module_1.sanitizeArgs(value)];
1045
1043
  }
1046
1044
  break;
1047
1045
  }
@@ -1050,7 +1048,7 @@ class Request extends module_1.default {
1050
1048
  return [opt.toString()];
1051
1049
  default:
1052
1050
  if ((0, types_1.isArray)(opt)) {
1053
- return opt.filter(item => (0, types_1.isString)(item)).map((item) => module_1.default.sanitizeArgs(item));
1051
+ return opt.filter(item => (0, types_1.isString)(item)).map((item) => module_1.sanitizeArgs(item));
1054
1052
  }
1055
1053
  break;
1056
1054
  }
@@ -1059,7 +1057,7 @@ class Request extends module_1.default {
1059
1057
  }
1060
1058
  }
1061
1059
  }
1062
- if (!(0, types_1.isString)(pathname)) {
1060
+ if (!pathname) {
1063
1061
  if (this.host) {
1064
1062
  return Promise.reject((0, types_1.errorMessage)("aria2", "Invalid parameters", 'pathname'));
1065
1063
  }
@@ -1068,7 +1066,7 @@ class Request extends module_1.default {
1068
1066
  if ((this.host || this.hasOwnPermission()) && !this.canWrite(pathname = path.resolve(pathname.trim()))) {
1069
1067
  return Promise.reject((0, types_1.errorMessage)("aria2", "Unsupported access", pathname));
1070
1068
  }
1071
- if (!module_1.default.createDir(pathname)) {
1069
+ if (!module_1.createDir(pathname)) {
1072
1070
  return Promise.reject((0, types_1.errorMessage)("aria2", "Path is not a directory", pathname));
1073
1071
  }
1074
1072
  silent ?? (silent = this[kSingleton]);
@@ -1179,7 +1177,7 @@ class Request extends module_1.default {
1179
1177
  }
1180
1178
  }
1181
1179
  if (origin) {
1182
- const secure = this[kCerts]?.[1][origin] || (this.host ? TLS.FILE[origin] : null);
1180
+ const secure = this[kCerts]?.[1][origin] || this.host && TLS.FILE[origin];
1183
1181
  if (secure) {
1184
1182
  if (secure.ca && ignoreOpt('--ca-certificate')) {
1185
1183
  args.push(`--ca-certificate="${escapeQuote(secure.ca)}"`);
@@ -1234,8 +1232,8 @@ class Request extends module_1.default {
1234
1232
  args = binOpts.concat(args);
1235
1233
  }
1236
1234
  if (args.length) {
1237
- if (module_1.default.hasLogType(32768)) {
1238
- this.formatMessage(32768, 'ARIA2', ARIA2.BIN, args.join(' '), { ...module_1.default.LOG_STYLE_WARN });
1235
+ if (module_1.hasLogType(32768)) {
1236
+ this.formatMessage(32768, 'ARIA2', ARIA2.BIN, args.join(' '), { ...module_1.LOG_STYLE_WARN });
1239
1237
  }
1240
1238
  else {
1241
1239
  this.addLog(types_1.STATUS_TYPE.INFO, path.basename(ARIA2.BIN) + ' ' + args.join(' '), "aria2");
@@ -1250,7 +1248,7 @@ class Request extends module_1.default {
1250
1248
  closeTorrent(pid);
1251
1249
  reject(err);
1252
1250
  };
1253
- const { pid, stdout, stderr } = child_process.spawn(module_1.default.sanitizeCmd(ARIA2.BIN), args, { cwd: pathname, shell: true, signal: this.signal, uid: ARIA2.EXEC_UID, gid: ARIA2.EXEC_GID })
1251
+ const { pid, stdout, stderr } = child_process.spawn(module_1.sanitizeCmd(ARIA2.BIN), args, { cwd: pathname, shell: true, signal: this.signal, uid: ARIA2.EXEC_UID, gid: ARIA2.EXEC_GID })
1254
1252
  .on('exit', code => {
1255
1253
  closeTorrent(pid);
1256
1254
  if (aborted) {
@@ -1260,15 +1258,15 @@ class Request extends module_1.default {
1260
1258
  errorResponse(pid, (0, types_1.createAbortError)());
1261
1259
  return;
1262
1260
  }
1263
- if (!code) {
1264
- const currentTime = Date.now();
1265
- const pattern = /\|(OK|ERR|INPR)\s*\|\s*([^|]+)\|\s*(\d+)\|([^\n]+)/g;
1266
- const result = [];
1267
- let messageUnit, match;
1268
- while (match = pattern.exec(out)) {
1269
- if (match[4].startsWith('[MEMORY]')) {
1270
- continue;
1271
- }
1261
+ if (code) {
1262
+ reject((0, types_1.errorValue)(message || "Unknown", 'Exit status: ' + code));
1263
+ return;
1264
+ }
1265
+ const currentTime = Date.now();
1266
+ const result = [];
1267
+ let messageUnit;
1268
+ for (const match of out.matchAll(/\|(OK|ERR|INPR)\s*\|\s*([^|]+)\|\s*(\d+)\|([^\n]+)/g)) {
1269
+ if (!match[4].startsWith('[MEMORY]')) {
1272
1270
  const file = path.normalize(match[4].trim());
1273
1271
  switch (match[1]) {
1274
1272
  case 'OK':
@@ -1286,20 +1284,17 @@ class Request extends module_1.default {
1286
1284
  break;
1287
1285
  }
1288
1286
  }
1289
- if (result.length && !silent && LOG_HTTP && LOG_TIMEPROCESS) {
1290
- this.writeTimeProcess("aria2", uri, startTime, { type: 1024, queue: true, messageUnit, messageUnitMinWidth: 9, bypassLog: true });
1291
- }
1292
- this.addLog(result.length ? types_1.STATUS_TYPE.INFO : types_1.STATUS_TYPE.ERROR, out, currentTime, currentTime - startTime, "aria2", uri);
1293
- resolve(result);
1294
1287
  }
1295
- else {
1296
- reject((0, types_1.errorValue)(message || "Unknown", 'Exit status: ' + code));
1288
+ if (result.length && !silent && LOG_HTTP && LOG_TIMEPROCESS) {
1289
+ this.writeTimeProcess("aria2", uri, startTime, { type: 1024, queue: true, messageUnit, messageUnitMinWidth: 9, bypassLog: true });
1297
1290
  }
1291
+ this.addLog(result.length ? types_1.STATUS_TYPE.INFO : types_1.STATUS_TYPE.ERROR, out, currentTime, currentTime - startTime, "aria2", uri);
1292
+ resolve(result);
1298
1293
  })
1299
1294
  .on('error', err => errorResponse(pid, err));
1300
1295
  stdout.setEncoding('utf-8').on('data', (value) => out += value);
1301
1296
  stderr.setEncoding('utf-8').on('data', (value) => message += value);
1302
- if (pid !== undefined && module_1.default.isFile(uri, 'torrent')) {
1297
+ if (pid !== undefined && module_1.isFile(uri, 'torrent')) {
1303
1298
  if (!ARIA2.PID_TIMER) {
1304
1299
  const clearTimer = () => {
1305
1300
  clearInterval(ARIA2.PID_TIMER);
@@ -1320,24 +1315,22 @@ class Request extends module_1.default {
1320
1315
  }
1321
1316
  if (ARIA2.UPDATE_STATUS && !silent) {
1322
1317
  const item = ARIA2.PID_QUEUE.shift();
1323
- if (item) {
1324
- const broadcastId = item[2];
1325
- if (!ARIA2.UPDATE_BROADCAST_ONLY || broadcastId) {
1326
- let progressBar;
1327
- if (item[2]) {
1328
- progressBar = true;
1329
- }
1330
- else {
1331
- const current = (0, types_1.getLogCurrent)();
1332
- progressBar = current?.type === 128 && current.title === "aria2";
1333
- }
1334
- this.formatMessage(128, "aria2", ['Downloading...', (0, types_1.formatTime)(startTime, true)], (PLATFORM_WIN32 ? 'taskkill /f /pid' : 'kill') + ` ${item[0]} -> ` + item[1], { ...module_1.default.LOG_STYLE_INFO, progressBar, broadcastId });
1335
- }
1336
- ARIA2.PID_QUEUE.push(item);
1337
- }
1338
- else {
1318
+ if (!item) {
1339
1319
  clearTimer();
1320
+ return;
1340
1321
  }
1322
+ if ((!ARIA2.UPDATE_BROADCAST_ONLY || item[2]) && this.host?.logState !== 0) {
1323
+ let progressBar;
1324
+ if (item[2]) {
1325
+ progressBar = true;
1326
+ }
1327
+ else {
1328
+ const current = (0, types_1.getLogCurrent)();
1329
+ progressBar = current?.type === 128 && current.title === "aria2";
1330
+ }
1331
+ this.formatMessage(128, "aria2", ['Downloading...', (0, types_1.formatTime)(startTime, true)], (PLATFORM_WIN32 ? 'taskkill /f /pid' : 'kill') + ` ${item[0]} -> ` + item[1], { ...module_1.LOG_STYLE_INFO, progressBar, broadcastId: item[2] });
1332
+ }
1333
+ ARIA2.PID_QUEUE.push(item);
1341
1334
  }
1342
1335
  }, (ARIA2.UPDATE_STATUS || 30) * 1000);
1343
1336
  }
@@ -1360,16 +1353,16 @@ class Request extends module_1.default {
1360
1353
  }
1361
1354
  let host;
1362
1355
  if (this.host) {
1363
- host = (_o = HTTP.HOST)[_p = url.origin] || (_o[_p] = new host_1.default(url, HTTP.VERSION));
1356
+ host = (_o = HTTP.HOST)[_p = url.origin] || (_o[_p] = new host_1(url, HTTP.VERSION));
1364
1357
  }
1365
1358
  else {
1366
- host = (_q = this[kHostInfo])[_r = url.origin] || (_q[_r] = new host_1.default(url, this.httpVersion || 1));
1359
+ host = (_q = this[kHostInfo])[_r = url.origin] || (_q[_r] = new host_1(url, this.httpVersion || 1));
1367
1360
  }
1368
1361
  return { ...options, host, url };
1369
1362
  }
1370
1363
  open(uri, options) {
1371
1364
  var _o, _p;
1372
- let { host, url, httpVersion, method = 'GET', encoding, format, headers, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options;
1365
+ let { host, url, httpVersion, method = 'GET', search, encoding, format, headers, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options;
1373
1366
  const getting = method === 'GET';
1374
1367
  const posting = method === 'POST';
1375
1368
  if (format) {
@@ -1416,6 +1409,12 @@ class Request extends module_1.default {
1416
1409
  url = new URL(uri);
1417
1410
  options.url = url;
1418
1411
  }
1412
+ if (search) {
1413
+ for (const param in search) {
1414
+ url.searchParams.append(param, search[param]);
1415
+ }
1416
+ uri = url.href;
1417
+ }
1419
1418
  const checkEncoding = (response, statusCode, contentEncoding = '') => {
1420
1419
  switch (statusCode) {
1421
1420
  case 206:
@@ -1463,13 +1462,13 @@ class Request extends module_1.default {
1463
1462
  (_o = (headers || (headers = {})))['accept-encoding'] || (_o['accept-encoding'] = 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : ''));
1464
1463
  }
1465
1464
  if (secure) {
1466
- const certs = this[kCerts]?.[0][origin] || (this.host ? TLS.TEXT[origin] : null);
1465
+ const certs = this[kCerts]?.[0][origin] || this.host && TLS.TEXT[origin];
1467
1466
  if (certs) {
1468
1467
  ({ ca, cert, key, version: minVersion } = certs);
1469
1468
  }
1470
1469
  }
1471
1470
  if (!proxy && httpVersion !== 1 && ((httpVersion || host.version) === 2 && version !== 1 || secure && version === 2 && host.failed(2, true) === 0)) {
1472
- request = ((_p = this[kSession][0])[origin] || (_p[origin] = http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, minVersion, settings: localhost ? { maxFrameSize: 16777215, enablePush: false } : { enablePush: false } }))).request({ ...baseHeaders, ...host_1.default.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
1471
+ request = ((_p = this[kSession][0])[origin] || (_p[origin] = http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, minVersion, settings: localhost ? { maxFrameSize: 16777215, enablePush: false } : { enablePush: false } }))).request({ ...baseHeaders, ...host_1.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
1473
1472
  if (getting) {
1474
1473
  const listenerMap = {};
1475
1474
  const onEvent = request.on.bind(request);
@@ -1579,7 +1578,7 @@ class Request extends module_1.default {
1579
1578
  }
1580
1579
  }
1581
1580
  }
1582
- const basicAuth = host_1.default.getBasicAuth(url);
1581
+ const basicAuth = host_1.getBasicAuth(url);
1583
1582
  if (baseHeaders || basicAuth) {
1584
1583
  headers = { ...baseHeaders, ...basicAuth, ...headers };
1585
1584
  }
@@ -1735,7 +1734,7 @@ class Request extends module_1.default {
1735
1734
  };
1736
1735
  const addValue = (name, value) => {
1737
1736
  if (value !== undefined) {
1738
- const disposition = createPart(name) + module_1.default.asString(value) + "\r\n";
1737
+ const disposition = createPart(name) + module_1.asString(value) + "\r\n";
1739
1738
  write.append(disposition);
1740
1739
  contentLength += Buffer.byteLength(disposition);
1741
1740
  }
@@ -1754,7 +1753,7 @@ class Request extends module_1.default {
1754
1753
  try {
1755
1754
  if (typeof target === 'string') {
1756
1755
  filename || (filename = path.basename(target));
1757
- type || (type = module_1.default.lookupMime(filename));
1756
+ type || (type = module_1.lookupMime(filename));
1758
1757
  target = fs.readFileSync(target);
1759
1758
  }
1760
1759
  else if (target instanceof stream.Readable) {
@@ -1768,14 +1767,14 @@ class Request extends module_1.default {
1768
1767
  throw (0, types_1.errorMessage)('File', "Unknown", "multipart/form-data");
1769
1768
  }
1770
1769
  if (!type || !filename) {
1771
- const result = await module_1.default.resolveMime(target);
1770
+ const result = await module_1.resolveMime(target);
1772
1771
  let ext;
1773
1772
  if (result) {
1774
1773
  type || (type = result.mime);
1775
1774
  ext = result.ext;
1776
1775
  }
1777
1776
  else if (type) {
1778
- ext = module_1.default.lookupMime(type, true);
1777
+ ext = module_1.lookupMime(type, true);
1779
1778
  }
1780
1779
  if (ext && !filename) {
1781
1780
  filename = (0, types_1.generateUUID)() + '.' + ext;
@@ -1803,7 +1802,7 @@ class Request extends module_1.default {
1803
1802
  }
1804
1803
  }
1805
1804
  if (!valid) {
1806
- return Promise.reject((0, types_1.errorValue)('No files were detected', "multipart/form-data"));
1805
+ return Promise.reject((0, types_1.errorValue)("No files were attached", "multipart/form-data"));
1807
1806
  }
1808
1807
  }
1809
1808
  else {
@@ -1811,7 +1810,7 @@ class Request extends module_1.default {
1811
1810
  contentType = 'application/' + contentType.trim();
1812
1811
  }
1813
1812
  if (!(0, types_1.isPlainObject)(data)) {
1814
- data = module_1.default.asString(data);
1813
+ data = module_1.asString(data);
1815
1814
  }
1816
1815
  else if (contentType === "application/x-www-form-urlencoded") {
1817
1816
  data = qs.stringify(data);
@@ -1842,7 +1841,7 @@ class Request extends module_1.default {
1842
1841
  if (!closed) {
1843
1842
  closed = true;
1844
1843
  if (outStream && (0, types_1.isString)(pipeTo)) {
1845
- (0, lib_v4_1.cleanupStream)(outStream, pipeTo);
1844
+ (0, util_1.cleanupStream)(outStream, pipeTo);
1846
1845
  }
1847
1846
  reject(typeof err === 'string' ? new Error(err) : err);
1848
1847
  }
@@ -1859,10 +1858,10 @@ class Request extends module_1.default {
1859
1858
  try {
1860
1859
  const request = this.opts(href, opts);
1861
1860
  if (outStream && (0, types_1.isString)(pipeTo)) {
1862
- (0, lib_v4_1.cleanupStream)(outStream, pipeTo);
1861
+ (0, util_1.cleanupStream)(outStream, pipeTo);
1863
1862
  }
1864
1863
  if (pipeTo) {
1865
- if ((0, types_1.isString)(pipeTo)) {
1864
+ if (typeof pipeTo === 'string') {
1866
1865
  outStream = fs.createWriteStream(pipeTo, { emitClose: false, highWaterMark: request.host.localhost ? 65536 : 4096 });
1867
1866
  request.outStream = outStream;
1868
1867
  }
@@ -1874,7 +1873,7 @@ class Request extends module_1.default {
1874
1873
  request.httpVersion = httpVersion;
1875
1874
  }
1876
1875
  const client = this.open(href, request);
1877
- const { host, url, encoding, outFormat } = request;
1876
+ const { host, url, encoding, progressId, outFormat } = request;
1878
1877
  let buffer, aborted;
1879
1878
  ({ httpVersion, outAbort } = request);
1880
1879
  const isAborted = () => client.destroyed || httpVersion === 2 && client.aborted;
@@ -1915,9 +1914,11 @@ class Request extends module_1.default {
1915
1914
  const buffering = request.connected?.call(client, headers);
1916
1915
  const pipeline = pipeTo ? !(0, types_1.isString)(pipeTo) : false;
1917
1916
  const enabled = buffering !== false && !pipeline;
1918
- const readTimeout = this.readTimeout;
1919
- let mibsTime, delayTime;
1920
- if (log || readTimeout > 0) {
1917
+ const maxBufferSize = request.maxBufferSize ? (0, types_1.alignSize)(request.maxBufferSize) : 0;
1918
+ const { host: parent, readTimeout } = this;
1919
+ const contentLength = parent && progressId !== undefined ? parseInt(headers['content-length'] || '0') : 0;
1920
+ let dataLength = 0, mibsTime, delayTime;
1921
+ if (log || readTimeout > 0 || contentLength > 0) {
1921
1922
  client.once('readable', () => {
1922
1923
  if (readTimeout > 0) {
1923
1924
  timeout = setTimeout(() => {
@@ -1934,7 +1935,10 @@ class Request extends module_1.default {
1934
1935
  delayTime = Date.now() - this.startTime;
1935
1936
  break;
1936
1937
  }
1937
- mibsTime = process.hrtime();
1938
+ }
1939
+ mibsTime = process.hrtime();
1940
+ if (contentLength > 0) {
1941
+ parent.updateProgress("request", progressId, 0, 0, mibsTime);
1938
1942
  }
1939
1943
  });
1940
1944
  }
@@ -1954,6 +1958,19 @@ class Request extends module_1.default {
1954
1958
  else {
1955
1959
  buffer = typeof chunk === 'string' ? chunk : [chunk];
1956
1960
  }
1961
+ if (contentLength > 0) {
1962
+ dataLength += Buffer.byteLength(chunk, encoding);
1963
+ parent.updateProgress("request", progressId, dataLength, contentLength);
1964
+ }
1965
+ if (maxBufferSize > 0) {
1966
+ if (contentLength === 0) {
1967
+ dataLength += Buffer.byteLength(chunk, encoding);
1968
+ }
1969
+ if (dataLength > maxBufferSize) {
1970
+ abortResponse();
1971
+ throwError((0, types_1.errorValue)("Size limit was exceeded", href.toString()));
1972
+ }
1973
+ }
1957
1974
  });
1958
1975
  }
1959
1976
  client.once('end', () => {
@@ -1976,20 +1993,15 @@ class Request extends module_1.default {
1976
1993
  buffer = buffer.toString(encoding);
1977
1994
  }
1978
1995
  }
1996
+ dataLength = Buffer.byteLength(buffer, encoding);
1979
1997
  if (mibsTime) {
1980
- const unit = (Buffer.byteLength(buffer, encoding) * 8) / ((0, types_1.convertTime)(process.hrtime(mibsTime)) * 1000);
1981
- if (unit < 1) {
1982
- messageUnit = Math.ceil(unit * 1000) + 'KiB/s';
1983
- }
1984
- else if (unit < 1000) {
1985
- messageUnit = unit.toPrecision(3) + 'MiB/s';
1986
- }
1987
- else {
1988
- messageUnit = (unit / 1000).toPrecision(3) + 'GiB/s';
1989
- }
1998
+ messageUnit = (0, util_1.getTransferRate)(dataLength, (0, types_1.convertTime)(process.hrtime(mibsTime), false) * 1000);
1999
+ }
2000
+ if (contentLength > 0) {
2001
+ parent.updateProgress("request", progressId, dataLength, dataLength);
1990
2002
  }
1991
2003
  if (typeof buffer === 'string') {
1992
- if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le') {
2004
+ if (buffer.startsWith('\uFEFF') && encoding !== 'utf16le' && encoding !== 'utf-16le') {
1993
2005
  buffer = buffer.substring(1);
1994
2006
  }
1995
2007
  if (outFormat) {
@@ -2029,11 +2041,14 @@ class Request extends module_1.default {
2029
2041
  result = buffer;
2030
2042
  }
2031
2043
  }
2032
- else if (enabled && this.readExpect === 'always') {
2033
- throwError('No data received');
2034
- return;
2035
- }
2036
2044
  else {
2045
+ if (contentLength > 0) {
2046
+ parent.updateProgress("request", progressId, 0, contentLength);
2047
+ }
2048
+ if (enabled && this.readExpect === 'always') {
2049
+ throwError('No data received');
2050
+ return;
2051
+ }
2037
2052
  result = encoding && !pipeline ? '' : null;
2038
2053
  titleBgColor = 'bgBlue';
2039
2054
  }
@@ -2047,7 +2062,10 @@ class Request extends module_1.default {
2047
2062
  const redirectResponse = (statusCode, location) => {
2048
2063
  abortResponse();
2049
2064
  if (location) {
2050
- if (++redirects <= this._config.redirectLimit) {
2065
+ if (request.follow_redirect === false) {
2066
+ throwError(formatStatus(statusCode, 'Follow redirect was disabled'));
2067
+ }
2068
+ else if (++redirects <= this._config.redirectLimit) {
2051
2069
  downloadUri.call(this, Request.fromURL(url, location));
2052
2070
  }
2053
2071
  else {
@@ -2353,9 +2371,5 @@ class Request extends module_1.default {
2353
2371
  }
2354
2372
  }
2355
2373
  _a = kSingleton, _b = kHttpVersion, _c = kHeaders, _d = kCerts, _e = kConnectDns, _f = kPendingDns, _g = kConnectHttp, _h = kStatusOn, _j = kHeadersOn, _k = kDownloading, _l = kHostInfo, _m = kSession;
2356
- exports.default = Request;
2357
2374
 
2358
- if (exports.default) {
2359
- module.exports = exports.default;
2360
- module.exports.default = exports.default;
2361
- }
2375
+ module.exports = Request;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e-mc/request",
3
- "version": "0.8.6",
3
+ "version": "0.9.0",
4
4
  "description": "Request constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -20,11 +20,11 @@
20
20
  "license": "BSD 3-Clause",
21
21
  "homepage": "https://github.com/anpham6/e-mc#readme",
22
22
  "dependencies": {
23
- "@e-mc/module": "0.8.6",
24
- "@e-mc/types": "0.8.6",
23
+ "@e-mc/module": "0.9.0",
24
+ "@e-mc/types": "0.9.0",
25
25
  "combined-stream": "^1.0.8",
26
26
  "js-yaml": "^4.1.0",
27
- "picomatch": "^3.0.1",
27
+ "picomatch": "^4.0.2",
28
28
  "which": "^2.0.2"
29
29
  }
30
30
  }
package/util.d.ts CHANGED
@@ -1,4 +1,7 @@
1
+ import type { AuthValue } from '../types/lib/http';
2
+
1
3
  import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http';
4
+ import type { Readable, Writable } from 'stream';
2
5
 
3
6
  declare namespace util {
4
7
  function parseHeader<T = unknown>(headers: IncomingHttpHeaders, name: string): T | undefined;
@@ -12,6 +15,12 @@ declare namespace util {
12
15
  function asInt(value: unknown): number;
13
16
  function asFloat(value: unknown): number;
14
17
  function fromSeconds(value: unknown): number;
18
+ function getTransferRate(length: number, timeMs: number, unitSeparator?: string): string;
19
+ function hasSameStat(src: string, dest: string, keepEmpty?: boolean): boolean;
20
+ function hasSize(value: string, keepEmpty?: boolean): boolean;
21
+ function getSize(value: string, diskUsed?: boolean): number;
22
+ function byteLength(value: Bufferable, encoding?: BufferEncoding): number;
23
+ function cleanupStream(target: Readable | Writable, pathname?: string): void;
15
24
  }
16
25
 
17
26
  export = util;
package/util.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fromSeconds = exports.asFloat = exports.asInt = exports.trimPath = exports.isRetryable = exports.checkRetryable = exports.hasBasicAuth = exports.getBasicAuth = exports.normalizeHeaders = exports.parseHeader = void 0;
2
+ exports.cleanupStream = exports.byteLength = exports.hasSameStat = exports.getSize = exports.hasSize = exports.getTransferRate = exports.fromSeconds = exports.asFloat = exports.asInt = exports.trimPath = exports.isRetryable = exports.checkRetryable = exports.hasBasicAuth = exports.getBasicAuth = exports.normalizeHeaders = exports.parseHeader = void 0;
3
+ const path = require("path");
4
+ const fs = require("fs");
4
5
  const module_1 = require("@e-mc/module");
5
6
  const types_1 = require("@e-mc/types");
6
7
  const safeInt = (value) => value >= 0 ? Math.min(value, Number.MAX_SAFE_INTEGER) : NaN;
@@ -9,9 +10,8 @@ function parseHeader(headers, name) {
9
10
  if (value) {
10
11
  switch (name.toLowerCase()) {
11
12
  case 'content-disposition': {
12
- const pattern = /\bfilename(?:\*\s*=\s*UTF-8''([^\s;]+)|\s*=\s*(?:"([^"]+)"|([^\s;]+)))/gi;
13
- let result, match;
14
- while (match = pattern.exec(value)) {
13
+ let result;
14
+ for (const match of value.matchAll(/\bfilename(?:\*\s*=\s*UTF-8''([^\s;]+)|\s*=\s*(?:"([^"]+)"|([^\s;]+)))/gi)) {
15
15
  if (match[1]) {
16
16
  return decodeURIComponent(match[1]).trim();
17
17
  }
@@ -36,7 +36,7 @@ function normalizeHeaders(headers) {
36
36
  break;
37
37
  default:
38
38
  if (Array.isArray(value)) {
39
- value = value.map(out => module_1.default.asString(out).trim());
39
+ value = value.map(out => module_1.asString(out).trim());
40
40
  break;
41
41
  }
42
42
  continue;
@@ -57,7 +57,7 @@ function getBasicAuth(username, password) {
57
57
  exports.getBasicAuth = getBasicAuth;
58
58
  function hasBasicAuth(value) {
59
59
  try {
60
- return (0, types_1.isString)(new URL(value).username);
60
+ return new URL(value).username.length > 0;
61
61
  }
62
62
  catch {
63
63
  }
@@ -146,3 +146,75 @@ function fromSeconds(value) {
146
146
  }
147
147
  }
148
148
  exports.fromSeconds = fromSeconds;
149
+ function getTransferRate(length, timeMs, unitSeparator = '') {
150
+ const unit = (length * 8) / timeMs;
151
+ if (unit < 1) {
152
+ return Math.ceil(unit * 1000) + unitSeparator + 'KiB/s';
153
+ }
154
+ if (unit < 1000) {
155
+ return unit.toPrecision(3) + unitSeparator + 'MiB/s';
156
+ }
157
+ return (unit / 1000).toPrecision(3) + unitSeparator + 'GiB/s';
158
+ }
159
+ exports.getTransferRate = getTransferRate;
160
+ function hasSize(value, keepEmpty) {
161
+ try {
162
+ const statSrc = fs.statSync(value);
163
+ if (statSrc.size > 0) {
164
+ return true;
165
+ }
166
+ if (!keepEmpty) {
167
+ fs.unlinkSync(value);
168
+ }
169
+ }
170
+ catch {
171
+ }
172
+ return false;
173
+ }
174
+ exports.hasSize = hasSize;
175
+ function getSize(value, diskUsed) {
176
+ try {
177
+ return (diskUsed ? fs.lstatSync(value) : fs.statSync(value)).size;
178
+ }
179
+ catch {
180
+ return 0;
181
+ }
182
+ }
183
+ exports.getSize = getSize;
184
+ function hasSameStat(src, dest, keepEmpty) {
185
+ try {
186
+ if (fs.existsSync(dest)) {
187
+ const { size, mtimeMs } = fs.statSync(src);
188
+ if (size > 0) {
189
+ const statDest = fs.statSync(dest);
190
+ return size === statDest.size && mtimeMs === statDest.mtimeMs;
191
+ }
192
+ if (!keepEmpty) {
193
+ fs.unlinkSync(src);
194
+ }
195
+ }
196
+ }
197
+ catch {
198
+ }
199
+ return false;
200
+ }
201
+ exports.hasSameStat = hasSameStat;
202
+ function byteLength(value, encoding) {
203
+ return typeof value === 'string' && (path.isAbsolute(value) || module_1.isPath(value)) ? getSize(value) : Buffer.byteLength(value, encoding && (0, types_1.getEncoding)(encoding));
204
+ }
205
+ exports.byteLength = byteLength;
206
+ function cleanupStream(stream, uri) {
207
+ try {
208
+ stream.removeAllListeners();
209
+ stream.destroy();
210
+ if (uri && fs.existsSync(uri)) {
211
+ fs.unlinkSync(uri);
212
+ }
213
+ }
214
+ catch (err) {
215
+ if (!module_1.isErrorCode(err, 'ENOENT')) {
216
+ module_1.writeFail(["Unable to delete file", path.basename(uri)], err, 32);
217
+ }
218
+ }
219
+ }
220
+ exports.cleanupStream = cleanupStream;