urllib 3.25.0 → 4.0.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.
Files changed (38) hide show
  1. package/README.md +5 -16
  2. package/dist/commonjs/HttpAgent.d.ts +0 -1
  3. package/dist/commonjs/HttpAgent.js +1 -0
  4. package/dist/commonjs/HttpClient.d.ts +1 -3
  5. package/dist/commonjs/HttpClient.js +20 -43
  6. package/dist/commonjs/HttpClientError.js +1 -0
  7. package/dist/commonjs/IncomingHttpHeaders.d.ts +0 -1
  8. package/dist/commonjs/IncomingHttpHeaders.js +1 -0
  9. package/dist/commonjs/Request.d.ts +0 -4
  10. package/dist/commonjs/Request.js +1 -0
  11. package/dist/commonjs/Response.d.ts +0 -1
  12. package/dist/commonjs/Response.js +1 -0
  13. package/dist/commonjs/diagnosticsChannel.js +33 -35
  14. package/dist/commonjs/index.js +7 -9
  15. package/dist/commonjs/symbols.js +1 -0
  16. package/dist/commonjs/utils.d.ts +0 -1
  17. package/dist/commonjs/utils.js +6 -12
  18. package/dist/esm/HttpAgent.d.ts +0 -1
  19. package/dist/esm/HttpAgent.js +1 -0
  20. package/dist/esm/HttpClient.d.ts +1 -3
  21. package/dist/esm/HttpClient.js +17 -40
  22. package/dist/esm/HttpClientError.js +1 -0
  23. package/dist/esm/IncomingHttpHeaders.d.ts +0 -1
  24. package/dist/esm/IncomingHttpHeaders.js +1 -0
  25. package/dist/esm/Request.d.ts +0 -4
  26. package/dist/esm/Request.js +1 -0
  27. package/dist/esm/Response.d.ts +0 -1
  28. package/dist/esm/Response.js +1 -0
  29. package/dist/esm/diagnosticsChannel.js +32 -33
  30. package/dist/esm/index.js +2 -1
  31. package/dist/esm/symbols.js +1 -0
  32. package/dist/esm/utils.d.ts +0 -1
  33. package/dist/esm/utils.js +1 -5
  34. package/package.json +18 -23
  35. package/src/HttpClient.ts +18 -40
  36. package/src/diagnosticsChannel.ts +43 -40
  37. package/src/index.ts +1 -1
  38. package/src/utils.ts +1 -7
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "urllib",
3
- "version": "3.25.0",
3
+ "version": "4.0.0",
4
4
  "publishConfig": {
5
5
  "tag": "latest"
6
6
  },
7
- "description": "Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, cookies and more. Base undici fetch API.",
7
+ "description": "Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, timeout and more. Base undici API.",
8
8
  "keywords": [
9
9
  "urllib",
10
10
  "http",
@@ -39,42 +39,35 @@
39
39
  "test": "npm run lint && vitest run",
40
40
  "test-keepalive": "cross-env TEST_KEEPALIVE_COUNT=50 vitest run --test-timeout 180000 keep-alive-header.test.ts",
41
41
  "cov": "vitest run --coverage",
42
- "preci": "node scripts/pre_test.js",
43
- "ci": "npm run lint && npm run cov && node scripts/build_test.js",
44
- "contributor": "git-contributor",
42
+ "ci": "npm run lint && npm run cov && npm run prepublishOnly && attw --pack",
45
43
  "clean": "rm -rf dist",
46
44
  "prepublishOnly": "npm run build"
47
45
  },
48
46
  "dependencies": {
49
- "default-user-agent": "^1.0.0",
50
- "digest-header": "^1.0.0",
51
- "form-data-encoder": "^1.7.2",
52
- "formdata-node": "^4.3.3",
53
- "formstream": "^1.1.1",
47
+ "formstream": "^1.5.1",
54
48
  "mime-types": "^2.1.35",
55
- "pump": "^3.0.0",
56
- "qs": "^6.11.2",
57
- "type-fest": "^4.3.1",
58
- "undici": "^5.28.2",
59
- "ylru": "^1.3.2"
49
+ "qs": "^6.12.1",
50
+ "type-fest": "^4.20.1",
51
+ "undici": "^6.19.2",
52
+ "ylru": "^2.0.0"
60
53
  },
61
54
  "devDependencies": {
55
+ "@arethetypeswrong/cli": "^0.15.3",
56
+ "@eggjs/tsconfig": "^1.3.3",
62
57
  "@tsconfig/node18": "^18.2.1",
63
58
  "@tsconfig/strictest": "^2.0.2",
64
59
  "@types/busboy": "^1.5.0",
65
- "@types/default-user-agent": "^1.0.0",
66
60
  "@types/mime-types": "^2.1.1",
67
61
  "@types/node": "^20.2.1",
68
- "@types/pump": "^1.1.1",
62
+ "@types/proxy": "^1.0.4",
69
63
  "@types/qs": "^6.9.7",
70
64
  "@types/selfsigned": "^2.0.1",
71
65
  "@types/tar-stream": "^2.2.2",
72
- "@vitest/coverage-v8": "^1.3.1",
66
+ "@vitest/coverage-v8": "^1.6.0",
73
67
  "busboy": "^1.6.0",
74
68
  "cross-env": "^7.0.3",
75
- "eslint": "^8.25.0",
76
- "eslint-config-egg": "^12.1.0",
77
- "git-contributor": "^2.0.0",
69
+ "eslint": "8",
70
+ "eslint-config-egg": "13",
78
71
  "iconv-lite": "^0.6.3",
79
72
  "proxy": "^1.0.2",
80
73
  "selfsigned": "^2.0.1",
@@ -82,10 +75,10 @@
82
75
  "tshy": "^1.0.0",
83
76
  "tshy-after": "^1.0.0",
84
77
  "typescript": "^5.0.4",
85
- "vitest": "^1.3.1"
78
+ "vitest": "^1.6.0"
86
79
  },
87
80
  "engines": {
88
- "node": ">= 14.19.3"
81
+ "node": ">= 18.19.0"
89
82
  },
90
83
  "license": "MIT",
91
84
  "type": "module",
@@ -98,10 +91,12 @@
98
91
  "exports": {
99
92
  ".": {
100
93
  "import": {
94
+ "source": "./src/index.ts",
101
95
  "types": "./dist/esm/index.d.ts",
102
96
  "default": "./dist/esm/index.js"
103
97
  },
104
98
  "require": {
99
+ "source": "./src/index.ts",
105
100
  "types": "./dist/commonjs/index.d.ts",
106
101
  "default": "./dist/commonjs/index.js"
107
102
  }
package/src/HttpClient.ts CHANGED
@@ -11,34 +11,33 @@ import {
11
11
  } from 'node:zlib';
12
12
  import { Blob } from 'node:buffer';
13
13
  import { Readable, pipeline } from 'node:stream';
14
- import stream from 'node:stream';
14
+ import { pipeline as pipelinePromise } from 'node:stream/promises';
15
15
  import { basename } from 'node:path';
16
16
  import { createReadStream } from 'node:fs';
17
17
  import { format as urlFormat } from 'node:url';
18
18
  import { performance } from 'node:perf_hooks';
19
19
  import querystring from 'node:querystring';
20
+ import { setTimeout as sleep } from 'node:timers/promises';
20
21
  import {
21
- FormData as FormDataNative,
22
+ FormData,
22
23
  request as undiciRequest,
23
24
  Dispatcher,
24
25
  Agent,
25
26
  getGlobalDispatcher,
26
27
  Pool,
27
28
  } from 'undici';
29
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
30
+ // @ts-ignore
28
31
  import undiciSymbols from 'undici/lib/core/symbols.js';
29
- import { FormData as FormDataNode } from 'formdata-node';
30
- import { FormDataEncoder } from 'form-data-encoder';
31
- import createUserAgent from 'default-user-agent';
32
32
  import mime from 'mime-types';
33
33
  import qs from 'qs';
34
- import pump from 'pump';
35
34
  // Compatible with old style formstream
36
35
  import FormStream from 'formstream';
37
36
  import { HttpAgent, CheckAddressFunction } from './HttpAgent.js';
38
37
  import type { IncomingHttpHeaders } from './IncomingHttpHeaders.js';
39
38
  import { RequestURL, RequestOptions, HttpMethod, RequestMeta } from './Request.js';
40
39
  import { RawResponseWithMeta, HttpClientResponse, SocketInfo } from './Response.js';
41
- import { parseJSON, sleep, digestAuthHeader, globalId, performanceTime, isReadable } from './utils.js';
40
+ import { parseJSON, digestAuthHeader, globalId, performanceTime, isReadable } from './utils.js';
42
41
  import symbols from './symbols.js';
43
42
  import { initDiagnosticsChannel } from './diagnosticsChannel.js';
44
43
  import { HttpClientConnectTimeoutError, HttpClientRequestTimeoutError } from './HttpClientError.js';
@@ -49,24 +48,12 @@ type PropertyShouldBe<T, K extends keyof T, V> = Omit<T, K> & { [P in K]: V };
49
48
  type IUndiciRequestOption = PropertyShouldBe<UndiciRequestOption, 'headers', IncomingHttpHeaders>;
50
49
 
51
50
  const PROTO_RE = /^https?:\/\//i;
52
- const FormData = FormDataNative ?? FormDataNode;
53
- // impl promise pipeline on Node.js 14
54
- const pipelinePromise = stream.promises?.pipeline ?? function pipeline(...args: any[]) {
55
- return new Promise<void>((resolve, reject) => {
56
- pump(...args, (err?: Error) => {
57
- if (err) return reject(err);
58
- resolve();
59
- });
60
- });
61
- };
62
51
 
63
52
  function noop() {
64
53
  // noop
65
54
  }
66
55
 
67
56
  const debug = debuglog('urllib:HttpClient');
68
- // Node.js 14 or 16
69
- const isNode14Or16 = /v1[46]\./.test(process.version);
70
57
 
71
58
  export type ClientOptions = {
72
59
  defaultArgs?: RequestOptions;
@@ -125,7 +112,10 @@ class BlobFromStream {
125
112
  }
126
113
  }
127
114
 
128
- export const HEADER_USER_AGENT = createUserAgent('node-urllib', 'VERSION');
115
+ export const VERSION = 'VERSION';
116
+ // 'node-urllib/4.0.0 Node.js/18.19.0 (darwin; x64)'
117
+ export const HEADER_USER_AGENT =
118
+ `node-urllib/${VERSION} Node.js/${process.version.substring(1)} (${process.platform}; ${process.arch})`;
129
119
 
130
120
  function getFileName(stream: Readable) {
131
121
  const filePath: string = (stream as any).path;
@@ -207,13 +197,13 @@ export class HttpClient extends EventEmitter {
207
197
  getDispatcherPoolStats() {
208
198
  const agent = this.getDispatcher();
209
199
  // origin => Pool Instance
210
- const clients: Map<string, WeakRef<Pool>> | undefined = agent[undiciSymbols.kClients];
200
+ const clients: Map<string, WeakRef<Pool>> | undefined = Reflect.get(agent, undiciSymbols.kClients);
211
201
  const poolStatsMap: Record<string, PoolStat> = {};
212
202
  if (!clients) {
213
203
  return poolStatsMap;
214
204
  }
215
205
  for (const [ key, ref ] of clients) {
216
- const pool = ref.deref();
206
+ const pool = typeof ref.deref === 'function' ? ref.deref() : ref as unknown as Pool;
217
207
  const stats = pool?.stats;
218
208
  if (!stats) continue;
219
209
  poolStatsMap[key] = {
@@ -451,9 +441,11 @@ export class HttpClient extends EventEmitter {
451
441
  } else if (typeof args.files === 'string' || Buffer.isBuffer(args.files)) {
452
442
  uploadFiles.push([ 'file', args.files ]);
453
443
  } else if (typeof args.files === 'object') {
454
- for (const field in args.files) {
444
+ const files = args.files as Record<string, string | Readable | Buffer>;
445
+ for (const field in files) {
455
446
  // set custom fileName
456
- uploadFiles.push([ field, args.files[field], field ]);
447
+ const file = files[field];
448
+ uploadFiles.push([ field, file, field ]);
457
449
  }
458
450
  }
459
451
  // set normal fields first
@@ -478,18 +470,7 @@ export class HttpClient extends EventEmitter {
478
470
  isStreamingRequest = true;
479
471
  }
480
472
  }
481
-
482
- if (FormDataNative) {
483
- requestOptions.body = formData;
484
- } else {
485
- // Node.js 14 does not support spec-compliant FormData
486
- // https://github.com/octet-stream/form-data#usage
487
- const encoder = new FormDataEncoder(formData as any);
488
- Object.assign(headers, encoder.headers);
489
- // fix "Content-Length":"NaN"
490
- delete headers['Content-Length'];
491
- requestOptions.body = Readable.from(encoder);
492
- }
473
+ requestOptions.body = formData;
493
474
  } else if (args.content) {
494
475
  if (!isGETOrHEAD) {
495
476
  // handle content
@@ -507,7 +488,7 @@ export class HttpClient extends EventEmitter {
507
488
  || isReadable(args.data);
508
489
  if (isGETOrHEAD) {
509
490
  if (!isStringOrBufferOrReadable) {
510
- let query;
491
+ let query: string;
511
492
  if (args.nestedQuerystring) {
512
493
  query = qs.stringify(args.data);
513
494
  } else {
@@ -608,9 +589,6 @@ export class HttpClient extends EventEmitter {
608
589
  res = Object.assign(response.body, res);
609
590
  }
610
591
  } else if (args.writeStream) {
611
- if (isNode14Or16 && args.writeStream.destroyed) {
612
- throw new Error('writeStream is destroyed');
613
- }
614
592
  if (args.compressed === true && isCompressedContent) {
615
593
  const decoder = contentEncoding === 'gzip' ? createGunzip() : createBrotliDecompress();
616
594
  await pipelinePromise(response.body, decoder, args.writeStream);
@@ -20,15 +20,14 @@ let initedDiagnosticsChannel = false;
20
20
  // -> undici:request:trailers => { request, trailers }
21
21
 
22
22
  function subscribe(name: string, listener: (message: unknown, channelName: string | symbol) => void) {
23
- if (typeof diagnosticsChannel.subscribe === 'function') {
24
- diagnosticsChannel.subscribe(name, listener);
25
- } else {
26
- // TODO: support Node.js 14, will be removed on the next major version
27
- diagnosticsChannel.channel(name).subscribe(listener);
28
- }
23
+ diagnosticsChannel.subscribe(name, listener);
29
24
  }
30
25
 
31
- function formatSocket(socket: Socket) {
26
+ type SocketExtend = Socket & {
27
+ [key: symbol]: string | number | Date | undefined;
28
+ };
29
+
30
+ function formatSocket(socket: SocketExtend) {
32
31
  if (!socket) return socket;
33
32
  return {
34
33
  localAddress: socket[symbols.kSocketLocalAddress],
@@ -41,8 +40,7 @@ function formatSocket(socket: Socket) {
41
40
  }
42
41
 
43
42
  // make sure error contains socket info
44
- const kDestroy = Symbol('kDestroy');
45
- Socket.prototype[kDestroy] = Socket.prototype.destroy;
43
+ const destroySocket = Socket.prototype.destroy;
46
44
  Socket.prototype.destroy = function(err?: any) {
47
45
  if (err) {
48
46
  Object.defineProperty(err, symbols.kErrorSocket, {
@@ -51,12 +49,12 @@ Socket.prototype.destroy = function(err?: any) {
51
49
  value: this,
52
50
  });
53
51
  }
54
- return this[kDestroy](err);
52
+ return destroySocket.call(this, err);
55
53
  };
56
54
 
57
55
  function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol) {
58
56
  if (!kHandler) return;
59
- const handler = request[kHandler];
57
+ const handler = Reflect.get(request, kHandler);
60
58
  // maxRedirects = 0 will get [Symbol(handler)]: RequestHandler {
61
59
  // responseHeaders: null,
62
60
  // opaque: {
@@ -70,7 +68,7 @@ function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol
70
68
  }
71
69
 
72
70
  export function initDiagnosticsChannel() {
73
- // makre sure init global DiagnosticsChannel once
71
+ // make sure init global DiagnosticsChannel once
74
72
  if (initedDiagnosticsChannel) return;
75
73
  initedDiagnosticsChannel = true;
76
74
 
@@ -97,29 +95,27 @@ export function initDiagnosticsChannel() {
97
95
  opaque[symbols.kRequestTiming].queuing = performanceTime(opaque[symbols.kRequestStartTime]);
98
96
  });
99
97
 
100
- // diagnosticsChannel.channel('undici:client:beforeConnect')
101
-
102
98
  subscribe('undici:client:connectError', (message, name) => {
103
- const { error, connectParams } = message as DiagnosticsChannel.ClientConnectErrorMessage & { error: any };
104
- let { socket } = message as DiagnosticsChannel.ClientConnectErrorMessage;
105
- if (!socket && error[symbols.kErrorSocket]) {
106
- socket = error[symbols.kErrorSocket];
99
+ const { error, connectParams, socket } = message as DiagnosticsChannel.ClientConnectErrorMessage & { error: any, socket: SocketExtend };
100
+ let sock = socket;
101
+ if (!sock && error[symbols.kErrorSocket]) {
102
+ sock = error[symbols.kErrorSocket];
107
103
  }
108
- if (socket) {
109
- socket[symbols.kSocketId] = globalId('UndiciSocket');
110
- socket[symbols.kSocketConnectErrorTime] = new Date();
111
- socket[symbols.kHandledRequests] = 0;
112
- socket[symbols.kHandledResponses] = 0;
104
+ if (sock) {
105
+ sock[symbols.kSocketId] = globalId('UndiciSocket');
106
+ sock[symbols.kSocketConnectErrorTime] = new Date();
107
+ sock[symbols.kHandledRequests] = 0;
108
+ sock[symbols.kHandledResponses] = 0;
113
109
  // copy local address to symbol, avoid them be reset after request error throw
114
- if (socket.localAddress) {
115
- socket[symbols.kSocketLocalAddress] = socket.localAddress;
116
- socket[symbols.kSocketLocalPort] = socket.localPort;
110
+ if (sock.localAddress) {
111
+ sock[symbols.kSocketLocalAddress] = sock.localAddress;
112
+ sock[symbols.kSocketLocalPort] = sock.localPort;
117
113
  }
118
- socket[symbols.kSocketConnectProtocol] = connectParams.protocol;
119
- socket[symbols.kSocketConnectHost] = connectParams.host;
120
- socket[symbols.kSocketConnectPort] = connectParams.port;
114
+ sock[symbols.kSocketConnectProtocol] = connectParams.protocol;
115
+ sock[symbols.kSocketConnectHost] = connectParams.host;
116
+ sock[symbols.kSocketConnectPort] = connectParams.port;
121
117
  debug('[%s] Socket#%d connectError, connectParams: %o, error: %s, (sock: %o)',
122
- name, socket[symbols.kSocketId], connectParams, (error as Error).message, formatSocket(socket));
118
+ name, sock[symbols.kSocketId], connectParams, (error as Error).message, formatSocket(sock));
123
119
  } else {
124
120
  debug('[%s] connectError, connectParams: %o, error: %o',
125
121
  name, connectParams, error);
@@ -128,7 +124,7 @@ export function initDiagnosticsChannel() {
128
124
 
129
125
  // This message is published after a connection is established.
130
126
  subscribe('undici:client:connected', (message, name) => {
131
- const { socket, connectParams } = message as DiagnosticsChannel.ClientConnectedMessage;
127
+ const { socket, connectParams } = message as DiagnosticsChannel.ClientConnectedMessage & { socket: SocketExtend };
132
128
  socket[symbols.kSocketId] = globalId('UndiciSocket');
133
129
  socket[symbols.kSocketStartTime] = performance.now();
134
130
  socket[symbols.kSocketConnectedTime] = new Date();
@@ -145,11 +141,11 @@ export function initDiagnosticsChannel() {
145
141
 
146
142
  // This message is published right before the first byte of the request is written to the socket.
147
143
  subscribe('undici:client:sendHeaders', (message, name) => {
148
- const { request, socket } = message as DiagnosticsChannel.ClientSendHeadersMessage;
144
+ const { request, socket } = message as DiagnosticsChannel.ClientSendHeadersMessage & { socket: SocketExtend };
149
145
  const opaque = getRequestOpaque(request, kHandler);
150
146
  if (!opaque || !opaque[symbols.kRequestId]) return;
151
147
 
152
- socket[symbols.kHandledRequests]++;
148
+ (socket[symbols.kHandledRequests] as number)++;
153
149
  // attach socket to opaque
154
150
  opaque[symbols.kRequestSocket] = socket;
155
151
  debug('[%s] Request#%d send headers on Socket#%d (handled %d requests, sock: %o)',
@@ -158,11 +154,11 @@ export function initDiagnosticsChannel() {
158
154
 
159
155
  if (!opaque[symbols.kEnableRequestTiming]) return;
160
156
  opaque[symbols.kRequestTiming].requestHeadersSent = performanceTime(opaque[symbols.kRequestStartTime]);
161
- // first socket need to caculate the connected time
157
+ // first socket need to calculate the connected time
162
158
  if (socket[symbols.kHandledRequests] === 1) {
163
159
  // kSocketStartTime - kRequestStartTime = connected time
164
160
  opaque[symbols.kRequestTiming].connected =
165
- performanceTime(opaque[symbols.kRequestStartTime], socket[symbols.kSocketStartTime]);
161
+ performanceTime(opaque[symbols.kRequestStartTime], socket[symbols.kSocketStartTime] as number);
166
162
  }
167
163
  });
168
164
 
@@ -184,10 +180,15 @@ export function initDiagnosticsChannel() {
184
180
 
185
181
  // get socket from opaque
186
182
  const socket = opaque[symbols.kRequestSocket];
187
- socket[symbols.kHandledResponses]++;
188
- debug('[%s] Request#%d get %s response headers on Socket#%d (handled %d responses, sock: %o)',
189
- name, opaque[symbols.kRequestId], response.statusCode, socket[symbols.kSocketId], socket[symbols.kHandledResponses],
190
- formatSocket(socket));
183
+ if (socket) {
184
+ socket[symbols.kHandledResponses]++;
185
+ debug('[%s] Request#%d get %s response headers on Socket#%d (handled %d responses, sock: %o)',
186
+ name, opaque[symbols.kRequestId], response.statusCode, socket[symbols.kSocketId], socket[symbols.kHandledResponses],
187
+ formatSocket(socket));
188
+ } else {
189
+ debug('[%s] Request#%d get %s response headers on Unknown Socket',
190
+ name, opaque[symbols.kRequestId], response.statusCode);
191
+ }
191
192
 
192
193
  if (!opaque[symbols.kEnableRequestTiming]) return;
193
194
  opaque[symbols.kRequestTiming].waiting = performanceTime(opaque[symbols.kRequestStartTime]);
@@ -197,7 +198,9 @@ export function initDiagnosticsChannel() {
197
198
  subscribe('undici:request:trailers', (message, name) => {
198
199
  const { request } = message as DiagnosticsChannel.RequestTrailersMessage;
199
200
  const opaque = getRequestOpaque(request, kHandler);
200
- if (!opaque || !opaque[symbols.kRequestId]) return;
201
+ if (!opaque || !opaque[symbols.kRequestId]) {
202
+ return;
203
+ }
201
204
 
202
205
  debug('[%s] Request#%d get response body and trailers', name, opaque[symbols.kRequestId]);
203
206
 
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import LRU from 'ylru';
1
+ import { LRU } from 'ylru';
2
2
  import { HttpClient, HEADER_USER_AGENT } from './HttpClient.js';
3
3
  import { RequestOptions, RequestURL } from './Request.js';
4
4
 
package/src/utils.ts CHANGED
@@ -3,7 +3,7 @@ import { Readable } from 'node:stream';
3
3
  import { performance } from 'node:perf_hooks';
4
4
  import type { FixJSONCtlChars } from './Request.js';
5
5
 
6
- const JSONCtlCharsMap = {
6
+ const JSONCtlCharsMap: Record<string, string> = {
7
7
  '"': '\\"', // \u0022
8
8
  '\\': '\\\\', // \u005c
9
9
  '\b': '\\b', // \u0008
@@ -49,12 +49,6 @@ export function parseJSON(data: string, fixJSONCtlChars?: FixJSONCtlChars) {
49
49
  return data;
50
50
  }
51
51
 
52
- export function sleep(ms: number) {
53
- return new Promise<void>(resolve => {
54
- setTimeout(resolve, ms);
55
- });
56
- }
57
-
58
52
  function md5(s: string) {
59
53
  const sum = createHash('md5');
60
54
  sum.update(s, 'utf8');