wrangler 0.0.0-e2f9bb2 → 0.0.0-e322475
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/Cloudflare_CA.pem +18 -0
- package/README.md +3 -1
- package/bin/wrangler.js +36 -4
- package/kv-asset-handler.js +1 -0
- package/package.json +15 -7
- package/pages/functions/buildPlugin.ts +13 -0
- package/pages/functions/buildWorker.ts +14 -1
- package/pages/functions/template-plugin.ts +3 -2
- package/src/__tests__/configuration.test.ts +652 -229
- package/src/__tests__/dev.test.tsx +372 -79
- package/src/__tests__/helpers/mock-cfetch.ts +2 -2
- package/src/__tests__/helpers/mock-console.ts +11 -1
- package/src/__tests__/helpers/mock-dialogs.ts +75 -11
- package/src/__tests__/helpers/mock-process.ts +24 -0
- package/src/__tests__/index.test.ts +81 -72
- package/src/__tests__/init.test.ts +1360 -410
- package/src/__tests__/jest.setup.ts +38 -0
- package/src/__tests__/kv.test.ts +218 -152
- package/src/__tests__/logger.test.ts +26 -0
- package/src/__tests__/package-manager.test.ts +154 -7
- package/src/__tests__/pages.test.ts +478 -53
- package/src/__tests__/parse.test.ts +8 -0
- package/src/__tests__/publish.test.ts +1614 -333
- package/src/__tests__/r2.test.ts +55 -36
- package/src/__tests__/secret.test.ts +39 -4
- package/src/__tests__/user.test.ts +1 -0
- package/src/__tests__/whoami.test.tsx +34 -0
- package/src/abort.d.ts +3 -0
- package/src/bundle-reporter.tsx +29 -0
- package/src/bundle.ts +42 -7
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +25 -20
- package/src/config/config.ts +11 -2
- package/src/config/environment.ts +41 -15
- package/src/config/index.ts +162 -0
- package/src/config/validation-helpers.ts +10 -1
- package/src/config/validation.ts +234 -78
- package/src/create-worker-preview.ts +32 -22
- package/src/create-worker-upload-form.ts +22 -8
- package/src/dev/dev.tsx +48 -67
- package/src/dev/local.tsx +16 -7
- package/src/dev/remote.tsx +57 -21
- package/src/dev/use-esbuild.ts +1 -7
- package/src/dialogs.tsx +48 -0
- package/src/durable.ts +102 -0
- package/src/entry.ts +71 -10
- package/src/generate-auth-url.ts +33 -0
- package/src/generate-random-state.ts +16 -0
- package/src/git-client.ts +42 -0
- package/src/index.tsx +619 -338
- package/src/inspect.ts +39 -0
- package/src/kv.ts +116 -27
- package/src/logger.ts +8 -1
- package/src/open-in-browser.ts +3 -12
- package/src/package-manager.ts +50 -3
- package/src/pages.tsx +434 -207
- package/src/parse.ts +44 -5
- package/src/proxy.ts +66 -44
- package/src/publish.ts +407 -137
- package/src/sites.tsx +103 -28
- package/src/user.tsx +35 -26
- package/src/whoami.tsx +3 -2
- package/src/worker.ts +10 -1
- package/src/zones.ts +73 -0
- package/templates/new-worker-scheduled.js +17 -0
- package/templates/new-worker-scheduled.ts +32 -0
- package/templates/new-worker.ts +16 -1
- package/templates/no-op-worker.js +10 -0
- package/templates/static-asset-facade.js +2 -6
- package/wrangler-dist/cli.js +46122 -32396
- package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
- package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
- package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
- package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
- package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
- package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
- package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
- package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
- package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
- package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
- package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
- package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
- package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
- package/vendor/wrangler-mime/CHANGELOG.md +0 -289
- package/vendor/wrangler-mime/LICENSE +0 -21
- package/vendor/wrangler-mime/Mime.js +0 -97
- package/vendor/wrangler-mime/README.md +0 -187
- package/vendor/wrangler-mime/cli.js +0 -46
- package/vendor/wrangler-mime/index.js +0 -4
- package/vendor/wrangler-mime/lite.js +0 -4
- package/vendor/wrangler-mime/package.json +0 -52
- package/vendor/wrangler-mime/types/other.js +0 -1
- package/vendor/wrangler-mime/types/standard.js +0 -1
package/src/parse.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import TOML from "@iarna/toml";
|
|
4
4
|
import { formatMessagesSync } from "esbuild";
|
|
5
|
+
import { logger } from "./logger";
|
|
5
6
|
|
|
6
7
|
export type Message = {
|
|
7
8
|
text: string;
|
|
@@ -38,7 +39,7 @@ export function formatMessage(
|
|
|
38
39
|
const lines = formatMessagesSync([input], {
|
|
39
40
|
color,
|
|
40
41
|
kind: kind,
|
|
41
|
-
terminalWidth:
|
|
42
|
+
terminalWidth: logger.columns,
|
|
42
43
|
});
|
|
43
44
|
return lines.join("\n");
|
|
44
45
|
}
|
|
@@ -62,8 +63,6 @@ export class ParseError extends Error implements Message {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
66
|
-
|
|
67
66
|
const TOML_ERROR_NAME = "TomlError";
|
|
68
67
|
const TOML_ERROR_SUFFIX = " at row ";
|
|
69
68
|
|
|
@@ -77,7 +76,9 @@ type TomlError = Error & {
|
|
|
77
76
|
*/
|
|
78
77
|
export function parseTOML(input: string, file?: string): TOML.JsonMap | never {
|
|
79
78
|
try {
|
|
80
|
-
|
|
79
|
+
// Normalize CRLF to LF to avoid hitting https://github.com/iarna/iarna-toml/issues/33.
|
|
80
|
+
const normalizedInput = input.replace(/\r\n/g, "\n");
|
|
81
|
+
return TOML.parse(normalizedInput);
|
|
81
82
|
} catch (err) {
|
|
82
83
|
const { name, message, line, col } = err as TomlError;
|
|
83
84
|
if (name !== TOML_ERROR_NAME) {
|
|
@@ -98,10 +99,29 @@ export function parseTOML(input: string, file?: string): TOML.JsonMap | never {
|
|
|
98
99
|
|
|
99
100
|
const JSON_ERROR_SUFFIX = " in JSON at position ";
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* A minimal type describing a package.json file.
|
|
104
|
+
*/
|
|
105
|
+
export type PackageJSON = {
|
|
106
|
+
devDependencies?: Record<string, unknown>;
|
|
107
|
+
dependencies?: Record<string, unknown>;
|
|
108
|
+
scripts?: Record<string, unknown>;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A typed version of `parseJSON()`.
|
|
113
|
+
*/
|
|
114
|
+
export function parsePackageJSON<T extends PackageJSON = PackageJSON>(
|
|
115
|
+
input: string,
|
|
116
|
+
file?: string
|
|
117
|
+
): T {
|
|
118
|
+
return parseJSON<T>(input, file);
|
|
119
|
+
}
|
|
120
|
+
|
|
101
121
|
/**
|
|
102
122
|
* A wrapper around `JSON.parse` that throws a `ParseError`.
|
|
103
123
|
*/
|
|
104
|
-
export function parseJSON(input: string, file?: string):
|
|
124
|
+
export function parseJSON<T>(input: string, file?: string): T {
|
|
105
125
|
try {
|
|
106
126
|
return JSON.parse(input);
|
|
107
127
|
} catch (err) {
|
|
@@ -119,6 +139,25 @@ export function parseJSON(input: string, file?: string): any {
|
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Reads a file into a node Buffer.
|
|
144
|
+
*/
|
|
145
|
+
export function readFileSyncToBuffer(file: string): Buffer {
|
|
146
|
+
try {
|
|
147
|
+
return fs.readFileSync(file);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
const { message } = err as Error;
|
|
150
|
+
throw new ParseError({
|
|
151
|
+
text: `Could not read file: ${file}`,
|
|
152
|
+
notes: [
|
|
153
|
+
{
|
|
154
|
+
text: message.replace(file, resolve(file)),
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
122
161
|
/**
|
|
123
162
|
* Reads a file and parses it based on its type.
|
|
124
163
|
*/
|
package/src/proxy.ts
CHANGED
|
@@ -2,11 +2,13 @@ import { createServer as createHttpServer } from "node:http";
|
|
|
2
2
|
import { connect } from "node:http2";
|
|
3
3
|
import { createServer as createHttpsServer } from "node:https";
|
|
4
4
|
import WebSocket from "faye-websocket";
|
|
5
|
+
import { createHttpTerminator } from "http-terminator";
|
|
5
6
|
import { useEffect, useRef, useState } from "react";
|
|
6
7
|
import serveStatic from "serve-static";
|
|
7
8
|
import { getHttpsOptions } from "./https-options";
|
|
8
9
|
import { logger } from "./logger";
|
|
9
10
|
import type { CfPreviewToken } from "./create-worker-preview";
|
|
11
|
+
import type { HttpTerminator } from "http-terminator";
|
|
10
12
|
import type {
|
|
11
13
|
IncomingHttpHeaders,
|
|
12
14
|
RequestListener,
|
|
@@ -67,35 +69,48 @@ function rewriteRemoteHostToLocalHostInHeaders(
|
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
type PreviewProxy = {
|
|
73
|
+
server: HttpServer | HttpsServer;
|
|
74
|
+
terminator: HttpTerminator;
|
|
75
|
+
};
|
|
76
|
+
|
|
70
77
|
export function usePreviewServer({
|
|
71
78
|
previewToken,
|
|
72
|
-
|
|
79
|
+
assetDirectory,
|
|
73
80
|
localProtocol,
|
|
74
81
|
localPort: port,
|
|
75
82
|
ip,
|
|
76
83
|
}: {
|
|
77
84
|
previewToken: CfPreviewToken | undefined;
|
|
78
|
-
|
|
85
|
+
assetDirectory: string | undefined;
|
|
79
86
|
localProtocol: "https" | "http";
|
|
80
87
|
localPort: number;
|
|
81
88
|
ip: string;
|
|
82
89
|
}) {
|
|
83
90
|
/** Creates an HTTP/1 proxy that sends requests over HTTP/2. */
|
|
84
|
-
const [
|
|
91
|
+
const [proxy, setProxy] = useState<PreviewProxy>();
|
|
85
92
|
|
|
86
93
|
/**
|
|
87
94
|
* Create the instance of the local proxy server that will pass on
|
|
88
95
|
* requests to the preview worker.
|
|
89
96
|
*/
|
|
90
97
|
useEffect(() => {
|
|
91
|
-
if (
|
|
98
|
+
if (proxy === undefined) {
|
|
92
99
|
createProxyServer(localProtocol)
|
|
93
|
-
.then((
|
|
100
|
+
.then((server) => {
|
|
101
|
+
setProxy({
|
|
102
|
+
server,
|
|
103
|
+
terminator: createHttpTerminator({
|
|
104
|
+
server,
|
|
105
|
+
gracefulTerminationTimeout: 0,
|
|
106
|
+
}),
|
|
107
|
+
});
|
|
108
|
+
})
|
|
94
109
|
.catch(async (err) => {
|
|
95
110
|
logger.error("Failed to create proxy server:", err);
|
|
96
111
|
});
|
|
97
112
|
}
|
|
98
|
-
}, [
|
|
113
|
+
}, [proxy, localProtocol]);
|
|
99
114
|
|
|
100
115
|
/**
|
|
101
116
|
* When we're not connected / getting a fresh token on changes,
|
|
@@ -123,7 +138,7 @@ export function usePreviewServer({
|
|
|
123
138
|
}
|
|
124
139
|
|
|
125
140
|
useEffect(() => {
|
|
126
|
-
if (
|
|
141
|
+
if (proxy === undefined) {
|
|
127
142
|
return;
|
|
128
143
|
}
|
|
129
144
|
|
|
@@ -138,8 +153,8 @@ export function usePreviewServer({
|
|
|
138
153
|
// store the stream in a buffer so we can replay it later
|
|
139
154
|
streamBufferRef.current.push({ stream, headers });
|
|
140
155
|
};
|
|
141
|
-
|
|
142
|
-
cleanupListeners.push(() =>
|
|
156
|
+
proxy.server.on("stream", bufferStream);
|
|
157
|
+
cleanupListeners.push(() => proxy.server.off("stream", bufferStream));
|
|
143
158
|
|
|
144
159
|
const bufferRequestResponse = (
|
|
145
160
|
request: IncomingMessage,
|
|
@@ -149,9 +164,9 @@ export function usePreviewServer({
|
|
|
149
164
|
requestResponseBufferRef.current.push({ request, response });
|
|
150
165
|
};
|
|
151
166
|
|
|
152
|
-
|
|
167
|
+
proxy.server.on("request", bufferRequestResponse);
|
|
153
168
|
cleanupListeners.push(() =>
|
|
154
|
-
|
|
169
|
+
proxy.server.off("request", bufferRequestResponse)
|
|
155
170
|
);
|
|
156
171
|
return () => {
|
|
157
172
|
cleanupListeners.forEach((cleanup) => cleanup());
|
|
@@ -161,8 +176,6 @@ export function usePreviewServer({
|
|
|
161
176
|
// We have a token. Let's proxy requests to the preview end point.
|
|
162
177
|
const cleanupListeners: (() => void)[] = [];
|
|
163
178
|
|
|
164
|
-
const assetPath = typeof publicRoot === "string" ? publicRoot : null;
|
|
165
|
-
|
|
166
179
|
// create a ClientHttp2Session
|
|
167
180
|
const remote = connect(`https://${previewToken.host}`);
|
|
168
181
|
cleanupListeners.push(() => remote.destroy());
|
|
@@ -179,8 +192,8 @@ export function usePreviewServer({
|
|
|
179
192
|
port,
|
|
180
193
|
localProtocol
|
|
181
194
|
);
|
|
182
|
-
|
|
183
|
-
cleanupListeners.push(() =>
|
|
195
|
+
proxy.server.on("stream", handleStream);
|
|
196
|
+
cleanupListeners.push(() => proxy.server.off("stream", handleStream));
|
|
184
197
|
|
|
185
198
|
// flush and replay buffered streams
|
|
186
199
|
streamBufferRef.current.forEach((buffer) =>
|
|
@@ -210,6 +223,10 @@ export function usePreviewServer({
|
|
|
210
223
|
const request = message.pipe(remote.request(headers));
|
|
211
224
|
request.on("response", (responseHeaders) => {
|
|
212
225
|
const status = responseHeaders[":status"] ?? 500;
|
|
226
|
+
|
|
227
|
+
// log all requests to terminal
|
|
228
|
+
logger.log(new Date().toLocaleTimeString(), method, url, status);
|
|
229
|
+
|
|
213
230
|
rewriteRemoteHostToLocalHostInHeaders(
|
|
214
231
|
responseHeaders,
|
|
215
232
|
previewToken.host,
|
|
@@ -228,13 +245,13 @@ export function usePreviewServer({
|
|
|
228
245
|
|
|
229
246
|
// If an asset path is defined, check the file system
|
|
230
247
|
// for a file first and serve if it exists.
|
|
231
|
-
const actualHandleRequest =
|
|
232
|
-
? createHandleAssetsRequest(
|
|
248
|
+
const actualHandleRequest = assetDirectory
|
|
249
|
+
? createHandleAssetsRequest(assetDirectory, handleRequest)
|
|
233
250
|
: handleRequest;
|
|
234
251
|
|
|
235
|
-
|
|
252
|
+
proxy.server.on("request", actualHandleRequest);
|
|
236
253
|
cleanupListeners.push(() =>
|
|
237
|
-
|
|
254
|
+
proxy.server.off("request", actualHandleRequest)
|
|
238
255
|
);
|
|
239
256
|
|
|
240
257
|
// flush and replay buffered requests
|
|
@@ -266,18 +283,18 @@ export function usePreviewServer({
|
|
|
266
283
|
remoteWebsocketClient.close();
|
|
267
284
|
});
|
|
268
285
|
};
|
|
269
|
-
|
|
270
|
-
cleanupListeners.push(() =>
|
|
286
|
+
proxy.server.on("upgrade", handleUpgrade);
|
|
287
|
+
cleanupListeners.push(() => proxy.server.off("upgrade", handleUpgrade));
|
|
271
288
|
|
|
272
289
|
return () => {
|
|
273
290
|
cleanupListeners.forEach((cleanup) => cleanup());
|
|
274
291
|
};
|
|
275
292
|
}, [
|
|
276
293
|
previewToken,
|
|
277
|
-
|
|
294
|
+
assetDirectory,
|
|
278
295
|
port,
|
|
279
296
|
localProtocol,
|
|
280
|
-
|
|
297
|
+
proxy,
|
|
281
298
|
// We use a state value as a sigil to trigger reconnecting the server.
|
|
282
299
|
// It's not used inside the effect, so react-hooks/exhaustive-deps
|
|
283
300
|
// doesn't complain if it's not included in the dependency array.
|
|
@@ -289,7 +306,7 @@ export function usePreviewServer({
|
|
|
289
306
|
// containing component is mounted/unmounted.
|
|
290
307
|
useEffect(() => {
|
|
291
308
|
const abortController = new AbortController();
|
|
292
|
-
if (
|
|
309
|
+
if (proxy === undefined) {
|
|
293
310
|
return;
|
|
294
311
|
}
|
|
295
312
|
|
|
@@ -299,8 +316,10 @@ export function usePreviewServer({
|
|
|
299
316
|
abortSignal: abortController.signal,
|
|
300
317
|
})
|
|
301
318
|
.then(() => {
|
|
302
|
-
|
|
303
|
-
|
|
319
|
+
proxy.server.on("listening", () => {
|
|
320
|
+
logger.log(`⬣ Listening at ${localProtocol}://${ip}:${port}`);
|
|
321
|
+
});
|
|
322
|
+
proxy.server.listen(port, ip);
|
|
304
323
|
})
|
|
305
324
|
.catch((err) => {
|
|
306
325
|
if ((err as { code: string }).code !== "ABORT_ERR") {
|
|
@@ -309,17 +328,21 @@ export function usePreviewServer({
|
|
|
309
328
|
});
|
|
310
329
|
|
|
311
330
|
return () => {
|
|
312
|
-
proxyServer.close();
|
|
313
331
|
abortController.abort();
|
|
332
|
+
// Running `proxy.server.close()` does not close open connections, preventing the process from exiting.
|
|
333
|
+
// So we use this `terminator` to close all the connections and force the server to shutdown.
|
|
334
|
+
proxy.terminator
|
|
335
|
+
.terminate()
|
|
336
|
+
.catch(() => logger.error("Failed to terminate the proxy server."));
|
|
314
337
|
};
|
|
315
|
-
}, [port, ip,
|
|
338
|
+
}, [port, ip, proxy, localProtocol]);
|
|
316
339
|
}
|
|
317
340
|
|
|
318
341
|
function createHandleAssetsRequest(
|
|
319
|
-
|
|
342
|
+
assetDirectory: string,
|
|
320
343
|
handleRequest: RequestListener
|
|
321
344
|
) {
|
|
322
|
-
const handleAsset = serveStatic(
|
|
345
|
+
const handleAsset = serveStatic(assetDirectory, {
|
|
323
346
|
cacheControl: false,
|
|
324
347
|
});
|
|
325
348
|
return (request: IncomingMessage, response: ServerResponse) => {
|
|
@@ -349,15 +372,6 @@ async function createProxyServer(
|
|
|
349
372
|
: createHttpServer();
|
|
350
373
|
|
|
351
374
|
return server
|
|
352
|
-
.on("request", function (req, res) {
|
|
353
|
-
// log all requests
|
|
354
|
-
logger.log(
|
|
355
|
-
new Date().toLocaleTimeString(),
|
|
356
|
-
req.method,
|
|
357
|
-
req.url,
|
|
358
|
-
res.statusCode
|
|
359
|
-
);
|
|
360
|
-
})
|
|
361
375
|
.on("upgrade", (req) => {
|
|
362
376
|
// log all websocket connections
|
|
363
377
|
logger.log(
|
|
@@ -409,7 +423,7 @@ export async function waitForPortToBeAvailable(
|
|
|
409
423
|
): Promise<void> {
|
|
410
424
|
return new Promise((resolve, reject) => {
|
|
411
425
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
412
|
-
|
|
426
|
+
options.abortSignal.addEventListener("abort", () => {
|
|
413
427
|
const abortError = new Error("waitForPortToBeAvailable() aborted");
|
|
414
428
|
(abortError as Error & { code: string }).code = "ABORT_ERR";
|
|
415
429
|
doReject(abortError);
|
|
@@ -439,16 +453,24 @@ export async function waitForPortToBeAvailable(
|
|
|
439
453
|
// trying to make a server listen on that port, and retrying
|
|
440
454
|
// until it succeeds.
|
|
441
455
|
const server = createHttpServer();
|
|
456
|
+
const terminator = createHttpTerminator({
|
|
457
|
+
server,
|
|
458
|
+
gracefulTerminationTimeout: 0, // default 1000
|
|
459
|
+
});
|
|
460
|
+
|
|
442
461
|
server.on("error", (err) => {
|
|
443
462
|
// @ts-expect-error non standard property on Error
|
|
444
463
|
if (err.code !== "EADDRINUSE") {
|
|
445
464
|
doReject(err);
|
|
446
465
|
}
|
|
447
466
|
});
|
|
448
|
-
server.listen(port, () =>
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
467
|
+
server.listen(port, () =>
|
|
468
|
+
terminator
|
|
469
|
+
.terminate()
|
|
470
|
+
.then(doResolve, () =>
|
|
471
|
+
logger.error("Failed to terminate the port checker.")
|
|
472
|
+
)
|
|
473
|
+
);
|
|
452
474
|
}
|
|
453
475
|
});
|
|
454
476
|
}
|