@e-mc/request 0.9.12 → 0.9.13

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/README.md CHANGED
@@ -9,12 +9,12 @@
9
9
 
10
10
  ## Interface
11
11
 
12
- * [View Source](https://www.unpkg.com/@e-mc/types@0.9.12/lib/index.d.ts)
12
+ * [View Source](https://www.unpkg.com/@e-mc/types@0.9.13/lib/index.d.ts)
13
13
 
14
14
  ```typescript
15
15
  import type { IModule, ModuleConstructor } from "./index";
16
16
  import type { HttpAgentSettings, HttpProtocolVersion, HttpRequestClient, InternetProtocolVersion } from "./http";
17
- import type { ApplyOptions, Aria2Options, FormDataPart, HeadersOnCallback, HostConfig, OpenOptions, PostOptions, ProxySettings, ReadExpectType, RequestInit, StatusOnCallback } from "./request";
17
+ import type { ApplyOptions, Aria2Options, FormDataPart, HeadersOnCallback, HostConfig, OpenOptions, PostOptions, ProxySettings, PutOptions, ReadExpectType, RequestInit, StatusOnCallback } from "./request";
18
18
  import type { DnsLookupSettings, RequestModule, RequestSettings } from "./settings";
19
19
 
20
20
  import type { ClientRequest, OutgoingHttpHeaders } from "http";
@@ -47,7 +47,8 @@ interface IRequest extends IModule {
47
47
  opts(url: string | URL, options?: OpenOptions): HostConfig;
48
48
  open(uri: string | URL, options: OpenOptions): HttpRequestClient;
49
49
  head(uri: string | URL, options?: OpenOptions): ClientRequest;
50
- post(uri: string | URL, data: unknown, contentType: string): Promise<Buffer | string | null>;
50
+ put(uri: string | URL, data: unknown, options: PutOptions): Promise<Buffer | string | null>;
51
+ put(uri: string | URL, data: unknown, contentType?: string, options?: PutOptions): Promise<Buffer | string | null>;
51
52
  post(uri: string | URL, parts: FormDataPart[]): Promise<Buffer | string | null>;
52
53
  post(uri: string | URL, form: Record<string, unknown>, parts: FormDataPart[]): Promise<Buffer | string | null>;
53
54
  post(uri: string | URL, data: unknown, options: PostOptions): Promise<Buffer | string | null>;
@@ -201,9 +202,9 @@ instance.get("http://hostname/path/config.yml", options).then(data => {
201
202
 
202
203
  ## References
203
204
 
204
- - https://www.unpkg.com/@e-mc/types@0.9.12/lib/http.d.ts
205
- - https://www.unpkg.com/@e-mc/types@0.9.12/lib/request.d.ts
206
- - https://www.unpkg.com/@e-mc/types@0.9.12/lib/settings.d.ts
205
+ - https://www.unpkg.com/@e-mc/types@0.9.13/lib/http.d.ts
206
+ - https://www.unpkg.com/@e-mc/types@0.9.13/lib/request.d.ts
207
+ - https://www.unpkg.com/@e-mc/types@0.9.13/lib/settings.d.ts
207
208
 
208
209
  * https://www.npmjs.com/package/@types/node
209
210
 
package/index.js CHANGED
@@ -258,8 +258,8 @@ function validateCerts(certs) {
258
258
  }
259
259
  return [text, file];
260
260
  }
261
- function abortHeaders(href, request, options) {
262
- const reason = (0, types_1.errorValue)("Aborted by client", href);
261
+ function abortHeaders(href, request, options, statusCode = '') {
262
+ const reason = (0, types_1.errorMessage)(statusCode, "Aborted by client", href);
263
263
  const outAbort = options.outAbort;
264
264
  if (outAbort) {
265
265
  outAbort.abort(reason);
@@ -1059,13 +1059,14 @@ class Request extends module_1 {
1059
1059
  return Promise.reject(err);
1060
1060
  }
1061
1061
  }
1062
- let pathname, headers, binOpts, silent;
1062
+ let pathname, headers, binOpts, signal, silent;
1063
1063
  if (options) {
1064
1064
  if (typeof options === 'string') {
1065
1065
  pathname = options;
1066
1066
  }
1067
1067
  else {
1068
- ({ pathname, headers, binOpts, silent } = options);
1068
+ ({ pathname, binOpts, signal, silent } = options);
1069
+ headers = (0, util_1.parseOutgoingHeaders)(options.headers);
1069
1070
  if ((0, types_1.isArray)(binOpts)) {
1070
1071
  let next = false;
1071
1072
  binOpts = binOpts.filter(opt => !((0, types_1.isString)(opt) && /^-[a-z][\S\s]*$/i.test(opt.trim()))).map((opt) => {
@@ -1365,7 +1366,13 @@ class Request extends module_1 {
1365
1366
  }
1366
1367
  for (const item of ARIA2.PID_QUEUE) {
1367
1368
  try {
1368
- process.kill(item[0], 0);
1369
+ if (pid === item[0] && signal?.aborted) {
1370
+ process.kill(item[0]);
1371
+ closeTorrent(item[0]);
1372
+ }
1373
+ else {
1374
+ process.kill(item[0], 0);
1375
+ }
1369
1376
  }
1370
1377
  catch {
1371
1378
  closeTorrent(item[0]);
@@ -1418,9 +1425,17 @@ class Request extends module_1 {
1418
1425
  return { ...options, host, url };
1419
1426
  }
1420
1427
  open(uri, options) {
1421
- let { host, url, httpVersion, method = 'GET', search, encoding, format, headers, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options;
1422
- const getting = method === 'GET';
1423
- const posting = method === 'POST';
1428
+ let { host, url, httpVersion, method = 'GET', search, encoding, format, headers: outgoing, postData, keepAlive, agentTimeout, socketPath, timeout = this._config.connectTimeout, outStream } = options, headers = (0, util_1.parseOutgoingHeaders)(outgoing), getting = false, posting = false;
1429
+ switch (method = method.toUpperCase()) {
1430
+ case 'GET':
1431
+ case 'DELETE':
1432
+ getting = true;
1433
+ break;
1434
+ case 'POST':
1435
+ case 'PUT':
1436
+ posting = true;
1437
+ break;
1438
+ }
1424
1439
  if (format) {
1425
1440
  let parser;
1426
1441
  if ((0, types_1.isObject)(format)) {
@@ -1471,12 +1486,12 @@ class Request extends module_1 {
1471
1486
  }
1472
1487
  uri = url.href;
1473
1488
  }
1474
- const { hostname, origin, secure, localhost } = host;
1489
+ const { hostname, origin, secure } = host;
1475
1490
  const pathname = url.pathname + (socketPath ? '' : url.search);
1476
- const proxy = this.proxyOf(uri, localhost);
1491
+ const proxy = this.proxyOf(uri, host.localhost);
1477
1492
  const version = this.httpVersion;
1478
1493
  let request, ca, cert, key, minVersion, baseHeaders = this.headersOf(uri);
1479
- if (getting && this.acceptEncoding && !localhost && !baseHeaders?.['accept-encoding']) {
1494
+ if (getting && this.acceptEncoding && !host.localhost && !baseHeaders?.['accept-encoding']) {
1480
1495
  (headers ||= {})['accept-encoding'] ||= 'gzip, deflate, br' + (LIB_ZSTD ? ', zstd' : '');
1481
1496
  }
1482
1497
  if (secure) {
@@ -1486,7 +1501,7 @@ class Request extends module_1 {
1486
1501
  }
1487
1502
  }
1488
1503
  if (!proxy && httpVersion !== 1 && ((httpVersion || host.version) === 2 && version !== 1 || secure && version === 2 && host.failed(2, true) === 0)) {
1489
- request = (this[kSession][0][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 });
1504
+ request = (this[kSession][0][origin] ||= http2.connect(origin, { lookup: this.lookupDns(hostname), ca, cert, key, minVersion, settings: host.localhost ? { maxFrameSize: 16777215, enablePush: false } : { enablePush: false } })).request({ ...baseHeaders, ...host_1.getBasicAuth(url), ...headers, ':path': pathname, ':method': method });
1490
1505
  if (getting) {
1491
1506
  const listenerMap = {};
1492
1507
  const onEvent = request.on.bind(request);
@@ -1678,6 +1693,9 @@ class Request extends module_1 {
1678
1693
  const ac = new AbortController();
1679
1694
  this[kDownloading].add(options.outAbort = ac);
1680
1695
  stream.addAbortSignal(ac.signal, request);
1696
+ if (options.signal) {
1697
+ stream.addAbortSignal(options.signal, request);
1698
+ }
1681
1699
  this.signal.addEventListener('abort', () => ac.abort(new Error("Aborted by process")), { once: true });
1682
1700
  }
1683
1701
  if (posting) {
@@ -1697,8 +1715,21 @@ class Request extends module_1 {
1697
1715
  out.httpVersion = 1;
1698
1716
  return this.open(out.url, out);
1699
1717
  }
1718
+ async put(uri, data, contentType, options) {
1719
+ if ((0, types_1.isPlainObject)(contentType)) {
1720
+ options = contentType;
1721
+ }
1722
+ else {
1723
+ (options ||= {}).contentType = contentType;
1724
+ }
1725
+ options.method = 'PUT';
1726
+ if (options.contentType === "multipart/form-data") {
1727
+ options.contentType = "application/x-www-form-urlencoded";
1728
+ }
1729
+ return this.post(uri, data, options);
1730
+ }
1700
1731
  async post(uri, data, contentType, options) {
1701
- let parts;
1732
+ let putting = false, parts;
1702
1733
  if (Array.isArray(contentType)) {
1703
1734
  parts = contentType;
1704
1735
  contentType = undefined;
@@ -1706,9 +1737,10 @@ class Request extends module_1 {
1706
1737
  else {
1707
1738
  if ((0, types_1.isPlainObject)(contentType)) {
1708
1739
  options = contentType;
1740
+ putting = options.method === 'PUT';
1709
1741
  contentType = undefined;
1710
1742
  }
1711
- if (Array.isArray(data) && (!contentType || contentType === "multipart/form-data")) {
1743
+ if (!putting && Array.isArray(data) && (!contentType || contentType === "multipart/form-data")) {
1712
1744
  parts = data;
1713
1745
  data = undefined;
1714
1746
  }
@@ -1717,7 +1749,7 @@ class Request extends module_1 {
1717
1749
  if ((0, types_1.isPlainObject)(options)) {
1718
1750
  let formData;
1719
1751
  ({ formData, dataEncoding } = options);
1720
- if (formData) {
1752
+ if (!putting && formData) {
1721
1753
  (parts ||= []).push(...Array.isArray(formData) ? formData : [formData]);
1722
1754
  }
1723
1755
  else {
@@ -1727,14 +1759,14 @@ class Request extends module_1 {
1727
1759
  else {
1728
1760
  options = {};
1729
1761
  }
1730
- const headers = options.headers ||= {};
1762
+ const headers = (0, util_1.parseOutgoingHeaders)(options.headers ||= {});
1731
1763
  for (const attr in headers) {
1732
1764
  const name = attr.toLowerCase();
1733
1765
  if (name === 'content-type' || name === 'content-length') {
1734
1766
  delete headers[attr];
1735
1767
  }
1736
1768
  }
1737
- if (parts || contentType === "multipart/form-data" || contentType === 'form-data') {
1769
+ if (!putting && (parts || contentType === "multipart/form-data" || contentType === 'form-data')) {
1738
1770
  let valid;
1739
1771
  if ((0, types_1.isArray)(parts)) {
1740
1772
  const write = combined.create();
@@ -1837,7 +1869,9 @@ class Request extends module_1 {
1837
1869
  }
1838
1870
  headers['content-length'] = Buffer.byteLength(data, (0, types_1.getEncoding)(dataEncoding)).toString();
1839
1871
  }
1840
- options.method = 'POST';
1872
+ if (!putting) {
1873
+ options.method = 'POST';
1874
+ }
1841
1875
  options.httpVersion = 1;
1842
1876
  options.postData = data;
1843
1877
  headers['content-type'] = contentType || "text/plain";
@@ -1890,7 +1924,7 @@ class Request extends module_1 {
1890
1924
  }
1891
1925
  const client = this.open(href, request);
1892
1926
  const { host, url, encoding, progressId, outFormat } = request;
1893
- let buffer, aborted;
1927
+ let buffer, aborted = false;
1894
1928
  ({ httpVersion, outAbort } = request);
1895
1929
  const isAborted = () => client.destroyed || httpVersion === 2 && client.aborted;
1896
1930
  const isRetry = (value) => (0, util_1.isRetryable)(value) && ++retries <= this._config.retryLimit;
@@ -1909,12 +1943,6 @@ class Request extends module_1 {
1909
1943
  }
1910
1944
  buffer = null;
1911
1945
  aborted = true;
1912
- if (outAbort) {
1913
- if (!client.aborted) {
1914
- outAbort.abort();
1915
- }
1916
- this[kDownloading].delete(outAbort);
1917
- }
1918
1946
  client.destroy();
1919
1947
  };
1920
1948
  const retryTimeout = () => {
@@ -1938,7 +1966,6 @@ class Request extends module_1 {
1938
1966
  client.once('readable', () => {
1939
1967
  if (readTimeout > 0) {
1940
1968
  timeout = setTimeout(() => {
1941
- abortResponse();
1942
1969
  throwError((0, types_1.errorValue)("Timeout was exceeded", href.toString()));
1943
1970
  }, readTimeout);
1944
1971
  }
@@ -1988,7 +2015,6 @@ class Request extends module_1 {
1988
2015
  dataLength += Buffer.byteLength(chunk, encoding);
1989
2016
  }
1990
2017
  if (dataLength > maxBufferSize) {
1991
- abortResponse();
1992
2018
  throwError((0, types_1.errorValue)("Size limit was exceeded", href.toString()));
1993
2019
  }
1994
2020
  }
@@ -2080,12 +2106,12 @@ class Request extends module_1 {
2080
2106
  host.success(httpVersion);
2081
2107
  };
2082
2108
  const redirectResponse = (statusCode, location) => {
2083
- abortResponse();
2084
2109
  if (location) {
2085
2110
  if (request.followRedirect === false || request.follow_redirect === false) {
2086
2111
  throwError(formatStatus(statusCode, 'Follow redirect was disabled'));
2087
2112
  }
2088
2113
  else if (++redirects <= this._config.redirectLimit) {
2114
+ abortResponse();
2089
2115
  downloadUri.call(this, Request.fromURL(url, location));
2090
2116
  }
2091
2117
  else {
@@ -2097,11 +2123,11 @@ class Request extends module_1 {
2097
2123
  }
2098
2124
  };
2099
2125
  const errorResponse = (err) => {
2100
- abortResponse();
2101
2126
  if (wasAborted(err)) {
2102
2127
  throwError(err);
2103
2128
  }
2104
2129
  else if ((0, util_1.checkRetryable)(err) && ++retries <= this._config.retryLimit) {
2130
+ abortResponse();
2105
2131
  if (isConnectionTimeout(err)) {
2106
2132
  retryTimeout();
2107
2133
  }
@@ -2247,7 +2273,6 @@ class Request extends module_1 {
2247
2273
  retryResponse(statusCode, res.headers['retry-after']);
2248
2274
  }
2249
2275
  else {
2250
- abortResponse();
2251
2276
  throwError(formatStatus(statusCode));
2252
2277
  }
2253
2278
  })
@@ -2265,8 +2290,8 @@ class Request extends module_1 {
2265
2290
  if (aborted) {
2266
2291
  return;
2267
2292
  }
2268
- abortResponse();
2269
2293
  if (++retries <= this._config.retryLimit) {
2294
+ abortResponse();
2270
2295
  retryTimeout();
2271
2296
  }
2272
2297
  else {
@@ -2307,7 +2332,7 @@ class Request extends module_1 {
2307
2332
  for (const callback of called) {
2308
2333
  try {
2309
2334
  if (callback(code, headers, url) === true) {
2310
- abortHeaders.call(this, href, request, options);
2335
+ abortHeaders.call(this, href, request, options, code);
2311
2336
  return false;
2312
2337
  }
2313
2338
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e-mc/request",
3
- "version": "0.9.12",
3
+ "version": "0.9.13",
4
4
  "description": "Request constructor for E-mc.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -17,11 +17,11 @@
17
17
  "squared-functions"
18
18
  ],
19
19
  "author": "An Pham <anpham6@gmail.com>",
20
- "license": "BSD 3-Clause",
20
+ "license": "BSD-3-Clause",
21
21
  "homepage": "https://github.com/anpham6/e-mc#readme",
22
22
  "dependencies": {
23
- "@e-mc/module": "0.9.12",
24
- "@e-mc/types": "0.9.12",
23
+ "@e-mc/module": "0.9.13",
24
+ "@e-mc/types": "0.9.13",
25
25
  "combined-stream": "^1.0.8",
26
26
  "js-yaml": "^4.1.0",
27
27
  "picomatch": "^4.0.2",
package/util.d.ts CHANGED
@@ -5,6 +5,7 @@ import type { Readable, Writable } from 'stream';
5
5
 
6
6
  declare namespace util {
7
7
  function parseHeader<T = unknown>(headers: IncomingHttpHeaders, name: string): T | undefined;
8
+ function parseOutgoingHeaders(headers: OutgoingHttpHeaders | Headers | undefined): OutgoingHttpHeaders | undefined;
8
9
  function normalizeHeaders(headers: OutgoingHttpHeaders): OutgoingHttpHeaders;
9
10
  function getBasicAuth(auth: AuthValue): string;
10
11
  function getBasicAuth(username: unknown, password?: unknown): string;
package/util.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
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;
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.parseOutgoingHeaders = exports.parseHeader = void 0;
3
3
  const path = require("path");
4
4
  const fs = require("fs");
5
5
  const util = require("util");
@@ -25,6 +25,24 @@ function parseHeader(headers, name) {
25
25
  }
26
26
  }
27
27
  exports.parseHeader = parseHeader;
28
+ function parseOutgoingHeaders(headers) {
29
+ if (headers) {
30
+ if (globalThis.Headers && headers instanceof Headers) {
31
+ const result = {};
32
+ headers.forEach((value, key) => {
33
+ if (key === 'set-cookie') {
34
+ (result[key] ||= []).push(value);
35
+ }
36
+ else {
37
+ result[key] = value;
38
+ }
39
+ });
40
+ return result;
41
+ }
42
+ return headers;
43
+ }
44
+ }
45
+ exports.parseOutgoingHeaders = parseOutgoingHeaders;
28
46
  function normalizeHeaders(headers) {
29
47
  const result = Object.create(null);
30
48
  for (const name in headers) {
@@ -37,11 +55,11 @@ function normalizeHeaders(headers) {
37
55
  value = value.trim();
38
56
  break;
39
57
  default:
40
- if (Array.isArray(value)) {
41
- value = value.map(out => module_1.asString(out).trim());
42
- break;
58
+ if (!(0, types_1.isArray)(value)) {
59
+ continue;
43
60
  }
44
- continue;
61
+ value = value.map(out => module_1.asString(out).trim());
62
+ break;
45
63
  }
46
64
  if (value) {
47
65
  result[trimPath(name.trim().toLowerCase())] = value;