wrangler 0.0.0-e3cab74 → 0.0.0-e452a35
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 +27 -14
- package/bin/wrangler.js +49 -5
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +42 -28
- package/pages/functions/buildPlugin.ts +105 -0
- package/pages/functions/buildWorker.ts +93 -4
- package/pages/functions/filepath-routing.test.ts +136 -25
- package/pages/functions/filepath-routing.ts +14 -3
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +147 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +1514 -367
- package/src/__tests__/dev.test.tsx +870 -84
- package/src/__tests__/guess-worker-format.test.ts +37 -18
- package/src/__tests__/helpers/mock-account-id.ts +22 -4
- package/src/__tests__/helpers/mock-cfetch.ts +8 -4
- package/src/__tests__/helpers/mock-console.ts +35 -10
- package/src/__tests__/helpers/mock-dialogs.ts +26 -1
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/helpers/mock-kv.ts +9 -16
- package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/mock-stdin.ts +103 -0
- package/src/__tests__/helpers/run-in-tmp.ts +10 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +130 -0
- package/src/__tests__/index.test.ts +137 -747
- package/src/__tests__/init.test.ts +1557 -0
- package/src/__tests__/jest.setup.ts +28 -8
- package/src/__tests__/kv.test.ts +598 -258
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +657 -0
- package/src/__tests__/parse.test.ts +8 -0
- package/src/__tests__/publish.test.ts +4003 -941
- package/src/__tests__/r2.test.ts +69 -34
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +228 -73
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +26 -7
- package/src/abort.d.ts +3 -0
- package/src/bundle.ts +74 -7
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +20 -14
- package/src/cli.ts +5 -11
- package/src/config/README.md +7 -7
- package/src/config/config.ts +69 -100
- package/src/config/environment.ts +119 -4
- package/src/config/index.ts +177 -4
- package/src/config/validation-helpers.ts +228 -23
- package/src/config/validation.ts +687 -174
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +74 -36
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +55 -18
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +422 -0
- package/src/dev/local.tsx +318 -0
- package/src/dev/remote.tsx +227 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +16 -6
- package/src/durable.ts +102 -0
- package/src/entry.ts +279 -14
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +123 -0
- package/src/index.tsx +1268 -806
- package/src/inspect.ts +64 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv.tsx → kv.ts} +195 -62
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/enum-keys.ts +17 -0
- package/src/miniflare-cli/index.ts +41 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +94 -6
- package/src/open-in-browser.ts +9 -3
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +1057 -75
- package/src/parse.ts +24 -5
- package/src/proxy.ts +143 -54
- package/src/publish.ts +444 -229
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +98 -44
- package/src/tail/index.ts +2 -2
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +263 -109
- package/src/whoami.tsx +2 -1
- package/src/{api/worker.ts → worker.ts} +24 -30
- package/templates/gitignore +171 -0
- package/templates/new-worker.ts +16 -1
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +55345 -69246
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/__tests__/logout.test.ts +0 -50
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/dev.tsx +0 -961
- package/src/guess-worker-format.ts +0 -68
- package/src/reporting.ts +0 -115
- package/wrangler-dist/cli.js.map +0 -7
package/src/parse.ts
CHANGED
|
@@ -62,8 +62,6 @@ export class ParseError extends Error implements Message {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
66
|
-
|
|
67
65
|
const TOML_ERROR_NAME = "TomlError";
|
|
68
66
|
const TOML_ERROR_SUFFIX = " at row ";
|
|
69
67
|
|
|
@@ -75,9 +73,11 @@ type TomlError = Error & {
|
|
|
75
73
|
/**
|
|
76
74
|
* A wrapper around `TOML.parse` that throws a `ParseError`.
|
|
77
75
|
*/
|
|
78
|
-
export function parseTOML(input: string, file?: string):
|
|
76
|
+
export function parseTOML(input: string, file?: string): TOML.JsonMap | never {
|
|
79
77
|
try {
|
|
80
|
-
|
|
78
|
+
// Normalize CRLF to LF to avoid hitting https://github.com/iarna/iarna-toml/issues/33.
|
|
79
|
+
const normalizedInput = input.replace(/\r\n/g, "\n");
|
|
80
|
+
return TOML.parse(normalizedInput);
|
|
81
81
|
} catch (err) {
|
|
82
82
|
const { name, message, line, col } = err as TomlError;
|
|
83
83
|
if (name !== TOML_ERROR_NAME) {
|
|
@@ -98,10 +98,29 @@ export function parseTOML(input: string, file?: string): object {
|
|
|
98
98
|
|
|
99
99
|
const JSON_ERROR_SUFFIX = " in JSON at position ";
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* A minimal type describing a package.json file.
|
|
103
|
+
*/
|
|
104
|
+
export type PackageJSON = {
|
|
105
|
+
devDependencies?: Record<string, unknown>;
|
|
106
|
+
dependencies?: Record<string, unknown>;
|
|
107
|
+
scripts?: Record<string, unknown>;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A typed version of `parseJSON()`.
|
|
112
|
+
*/
|
|
113
|
+
export function parsePackageJSON<T extends PackageJSON = PackageJSON>(
|
|
114
|
+
input: string,
|
|
115
|
+
file?: string
|
|
116
|
+
): T {
|
|
117
|
+
return parseJSON<T>(input, file);
|
|
118
|
+
}
|
|
119
|
+
|
|
101
120
|
/**
|
|
102
121
|
* A wrapper around `JSON.parse` that throws a `ParseError`.
|
|
103
122
|
*/
|
|
104
|
-
export function parseJSON(input: string, file?: string):
|
|
123
|
+
export function parseJSON<T>(input: string, file?: string): T {
|
|
105
124
|
try {
|
|
106
125
|
return JSON.parse(input);
|
|
107
126
|
} catch (err) {
|
package/src/proxy.ts
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { createServer } from "node:http";
|
|
1
|
+
import { createServer as createHttpServer } from "node:http";
|
|
2
2
|
import { connect } from "node:http2";
|
|
3
|
+
import { createServer as createHttpsServer } from "node:https";
|
|
3
4
|
import WebSocket from "faye-websocket";
|
|
5
|
+
import { createHttpTerminator } from "http-terminator";
|
|
4
6
|
import { useEffect, useRef, useState } from "react";
|
|
5
7
|
import serveStatic from "serve-static";
|
|
6
|
-
import
|
|
8
|
+
import { getHttpsOptions } from "./https-options";
|
|
9
|
+
import { logger } from "./logger";
|
|
10
|
+
import type { CfPreviewToken } from "./create-worker-preview";
|
|
11
|
+
import type { HttpTerminator } from "http-terminator";
|
|
7
12
|
import type {
|
|
8
13
|
IncomingHttpHeaders,
|
|
9
14
|
RequestListener,
|
|
10
15
|
IncomingMessage,
|
|
11
16
|
ServerResponse,
|
|
12
|
-
Server,
|
|
17
|
+
Server as HttpServer,
|
|
13
18
|
} from "node:http";
|
|
14
19
|
import type { ClientHttp2Session, ServerHttp2Stream } from "node:http2";
|
|
20
|
+
import type { Server as HttpsServer } from "node:https";
|
|
15
21
|
import type ws from "ws";
|
|
16
22
|
|
|
17
23
|
interface IWebsocket extends ws {
|
|
@@ -47,30 +53,61 @@ function addCfPreviewTokenHeader(
|
|
|
47
53
|
function rewriteRemoteHostToLocalHostInHeaders(
|
|
48
54
|
headers: IncomingHttpHeaders,
|
|
49
55
|
remoteHost: string,
|
|
50
|
-
localPort: number
|
|
56
|
+
localPort: number,
|
|
57
|
+
localProtocol: "https" | "http"
|
|
51
58
|
) {
|
|
52
59
|
for (const [name, value] of Object.entries(headers)) {
|
|
53
60
|
// Rewrite the remote host to the local host.
|
|
54
61
|
if (typeof value === "string" && value.includes(remoteHost)) {
|
|
55
62
|
headers[name] = value
|
|
56
|
-
.replaceAll(
|
|
63
|
+
.replaceAll(
|
|
64
|
+
`https://${remoteHost}`,
|
|
65
|
+
`${localProtocol}://localhost:${localPort}`
|
|
66
|
+
)
|
|
57
67
|
.replaceAll(remoteHost, `localhost:${localPort}`);
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
|
|
72
|
+
type PreviewProxy = {
|
|
73
|
+
server: HttpServer | HttpsServer;
|
|
74
|
+
terminator: HttpTerminator;
|
|
75
|
+
};
|
|
76
|
+
|
|
62
77
|
export function usePreviewServer({
|
|
63
78
|
previewToken,
|
|
64
79
|
publicRoot,
|
|
65
|
-
|
|
80
|
+
localProtocol,
|
|
81
|
+
localPort: port,
|
|
82
|
+
ip,
|
|
66
83
|
}: {
|
|
67
84
|
previewToken: CfPreviewToken | undefined;
|
|
68
|
-
publicRoot:
|
|
69
|
-
|
|
85
|
+
publicRoot: string | undefined;
|
|
86
|
+
localProtocol: "https" | "http";
|
|
87
|
+
localPort: number;
|
|
88
|
+
ip: string;
|
|
70
89
|
}) {
|
|
71
90
|
/** Creates an HTTP/1 proxy that sends requests over HTTP/2. */
|
|
72
|
-
const
|
|
73
|
-
|
|
91
|
+
const [proxy, setProxy] = useState<PreviewProxy>();
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create the instance of the local proxy server that will pass on
|
|
95
|
+
* requests to the preview worker.
|
|
96
|
+
*/
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (proxy === undefined) {
|
|
99
|
+
createProxyServer(localProtocol)
|
|
100
|
+
.then((server) => {
|
|
101
|
+
setProxy({
|
|
102
|
+
server,
|
|
103
|
+
terminator: createHttpTerminator({ server }),
|
|
104
|
+
});
|
|
105
|
+
})
|
|
106
|
+
.catch(async (err) => {
|
|
107
|
+
logger.error("Failed to create proxy server:", err);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}, [proxy, localProtocol]);
|
|
74
111
|
|
|
75
112
|
/**
|
|
76
113
|
* When we're not connected / getting a fresh token on changes,
|
|
@@ -98,6 +135,10 @@ export function usePreviewServer({
|
|
|
98
135
|
}
|
|
99
136
|
|
|
100
137
|
useEffect(() => {
|
|
138
|
+
if (proxy === undefined) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
101
142
|
// If we don't have a token, that means either we're just starting up,
|
|
102
143
|
// or we're refreshing the token.
|
|
103
144
|
if (!previewToken) {
|
|
@@ -109,8 +150,8 @@ export function usePreviewServer({
|
|
|
109
150
|
// store the stream in a buffer so we can replay it later
|
|
110
151
|
streamBufferRef.current.push({ stream, headers });
|
|
111
152
|
};
|
|
112
|
-
proxy.on("stream", bufferStream);
|
|
113
|
-
cleanupListeners.push(() => proxy.off("stream", bufferStream));
|
|
153
|
+
proxy.server.on("stream", bufferStream);
|
|
154
|
+
cleanupListeners.push(() => proxy.server.off("stream", bufferStream));
|
|
114
155
|
|
|
115
156
|
const bufferRequestResponse = (
|
|
116
157
|
request: IncomingMessage,
|
|
@@ -120,8 +161,10 @@ export function usePreviewServer({
|
|
|
120
161
|
requestResponseBufferRef.current.push({ request, response });
|
|
121
162
|
};
|
|
122
163
|
|
|
123
|
-
proxy.on("request", bufferRequestResponse);
|
|
124
|
-
cleanupListeners.push(() =>
|
|
164
|
+
proxy.server.on("request", bufferRequestResponse);
|
|
165
|
+
cleanupListeners.push(() =>
|
|
166
|
+
proxy.server.off("request", bufferRequestResponse)
|
|
167
|
+
);
|
|
125
168
|
return () => {
|
|
126
169
|
cleanupListeners.forEach((cleanup) => cleanup());
|
|
127
170
|
};
|
|
@@ -142,9 +185,14 @@ export function usePreviewServer({
|
|
|
142
185
|
cleanupListeners.push(() => remote.off("close", retryServerSetup));
|
|
143
186
|
|
|
144
187
|
/** HTTP/2 -> HTTP/2 */
|
|
145
|
-
const handleStream = createStreamHandler(
|
|
146
|
-
|
|
147
|
-
|
|
188
|
+
const handleStream = createStreamHandler(
|
|
189
|
+
previewToken,
|
|
190
|
+
remote,
|
|
191
|
+
port,
|
|
192
|
+
localProtocol
|
|
193
|
+
);
|
|
194
|
+
proxy.server.on("stream", handleStream);
|
|
195
|
+
cleanupListeners.push(() => proxy.server.off("stream", handleStream));
|
|
148
196
|
|
|
149
197
|
// flush and replay buffered streams
|
|
150
198
|
streamBufferRef.current.forEach((buffer) =>
|
|
@@ -174,10 +222,15 @@ export function usePreviewServer({
|
|
|
174
222
|
const request = message.pipe(remote.request(headers));
|
|
175
223
|
request.on("response", (responseHeaders) => {
|
|
176
224
|
const status = responseHeaders[":status"] ?? 500;
|
|
225
|
+
|
|
226
|
+
// log all requests to terminal
|
|
227
|
+
logger.log(new Date().toLocaleTimeString(), method, url, status);
|
|
228
|
+
|
|
177
229
|
rewriteRemoteHostToLocalHostInHeaders(
|
|
178
230
|
responseHeaders,
|
|
179
231
|
previewToken.host,
|
|
180
|
-
port
|
|
232
|
+
port,
|
|
233
|
+
localProtocol
|
|
181
234
|
);
|
|
182
235
|
for (const name of Object.keys(responseHeaders)) {
|
|
183
236
|
if (name.startsWith(":")) {
|
|
@@ -195,8 +248,10 @@ export function usePreviewServer({
|
|
|
195
248
|
? createHandleAssetsRequest(assetPath, handleRequest)
|
|
196
249
|
: handleRequest;
|
|
197
250
|
|
|
198
|
-
proxy.on("request", actualHandleRequest);
|
|
199
|
-
cleanupListeners.push(() =>
|
|
251
|
+
proxy.server.on("request", actualHandleRequest);
|
|
252
|
+
cleanupListeners.push(() =>
|
|
253
|
+
proxy.server.off("request", actualHandleRequest)
|
|
254
|
+
);
|
|
200
255
|
|
|
201
256
|
// flush and replay buffered requests
|
|
202
257
|
requestResponseBufferRef.current.forEach(({ request, response }) =>
|
|
@@ -227,8 +282,8 @@ export function usePreviewServer({
|
|
|
227
282
|
remoteWebsocketClient.close();
|
|
228
283
|
});
|
|
229
284
|
};
|
|
230
|
-
proxy.on("upgrade", handleUpgrade);
|
|
231
|
-
cleanupListeners.push(() => proxy.off("upgrade", handleUpgrade));
|
|
285
|
+
proxy.server.on("upgrade", handleUpgrade);
|
|
286
|
+
cleanupListeners.push(() => proxy.server.off("upgrade", handleUpgrade));
|
|
232
287
|
|
|
233
288
|
return () => {
|
|
234
289
|
cleanupListeners.forEach((cleanup) => cleanup());
|
|
@@ -237,6 +292,7 @@ export function usePreviewServer({
|
|
|
237
292
|
previewToken,
|
|
238
293
|
publicRoot,
|
|
239
294
|
port,
|
|
295
|
+
localProtocol,
|
|
240
296
|
proxy,
|
|
241
297
|
// We use a state value as a sigil to trigger reconnecting the server.
|
|
242
298
|
// It's not used inside the effect, so react-hooks/exhaustive-deps
|
|
@@ -248,19 +304,35 @@ export function usePreviewServer({
|
|
|
248
304
|
// Start/stop the server whenever the
|
|
249
305
|
// containing component is mounted/unmounted.
|
|
250
306
|
useEffect(() => {
|
|
251
|
-
|
|
307
|
+
const abortController = new AbortController();
|
|
308
|
+
if (proxy === undefined) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
waitForPortToBeAvailable(port, {
|
|
313
|
+
retryPeriod: 200,
|
|
314
|
+
timeout: 2000,
|
|
315
|
+
abortSignal: abortController.signal,
|
|
316
|
+
})
|
|
252
317
|
.then(() => {
|
|
253
|
-
proxy.
|
|
254
|
-
|
|
318
|
+
proxy.server.on("listening", () => {
|
|
319
|
+
logger.log(`⬣ Listening at ${localProtocol}://${ip}:${port}`);
|
|
320
|
+
});
|
|
321
|
+
proxy.server.listen(port, ip);
|
|
255
322
|
})
|
|
256
323
|
.catch((err) => {
|
|
257
|
-
|
|
324
|
+
if ((err as { code: string }).code !== "ABORT_ERR") {
|
|
325
|
+
logger.error(`Failed to start server: ${err}`);
|
|
326
|
+
}
|
|
258
327
|
});
|
|
259
328
|
|
|
260
329
|
return () => {
|
|
261
|
-
|
|
330
|
+
abortController.abort();
|
|
331
|
+
// Running `proxy.server.close()` does not close open connections, preventing the process from exiting.
|
|
332
|
+
// So we use this `terminator` to close all the connections and force the server to shutdown.
|
|
333
|
+
proxy.terminator.terminate();
|
|
262
334
|
};
|
|
263
|
-
}, [port, proxy]);
|
|
335
|
+
}, [port, ip, proxy, localProtocol]);
|
|
264
336
|
}
|
|
265
337
|
|
|
266
338
|
function createHandleAssetsRequest(
|
|
@@ -288,20 +360,18 @@ const HTTP1_HEADERS = new Set([
|
|
|
288
360
|
"http2-settings",
|
|
289
361
|
]);
|
|
290
362
|
|
|
291
|
-
function createProxyServer(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
);
|
|
301
|
-
})
|
|
363
|
+
async function createProxyServer(
|
|
364
|
+
localProtocol: "https" | "http"
|
|
365
|
+
): Promise<HttpServer | HttpsServer> {
|
|
366
|
+
const server: HttpServer | HttpsServer =
|
|
367
|
+
localProtocol === "https"
|
|
368
|
+
? createHttpsServer(await getHttpsOptions())
|
|
369
|
+
: createHttpServer();
|
|
370
|
+
|
|
371
|
+
return server
|
|
302
372
|
.on("upgrade", (req) => {
|
|
303
373
|
// log all websocket connections
|
|
304
|
-
|
|
374
|
+
logger.log(
|
|
305
375
|
new Date().toLocaleTimeString(),
|
|
306
376
|
req.method,
|
|
307
377
|
req.url,
|
|
@@ -311,14 +381,15 @@ function createProxyServer() {
|
|
|
311
381
|
})
|
|
312
382
|
.on("error", (err) => {
|
|
313
383
|
// log all connection errors
|
|
314
|
-
|
|
384
|
+
logger.error(new Date().toLocaleTimeString(), err);
|
|
315
385
|
});
|
|
316
386
|
}
|
|
317
387
|
|
|
318
388
|
function createStreamHandler(
|
|
319
389
|
previewToken: CfPreviewToken,
|
|
320
390
|
remote: ClientHttp2Session,
|
|
321
|
-
|
|
391
|
+
localPort: number,
|
|
392
|
+
localProtocol: "https" | "http"
|
|
322
393
|
) {
|
|
323
394
|
return function handleStream(
|
|
324
395
|
stream: ServerHttp2Stream,
|
|
@@ -331,7 +402,8 @@ function createStreamHandler(
|
|
|
331
402
|
rewriteRemoteHostToLocalHostInHeaders(
|
|
332
403
|
responseHeaders,
|
|
333
404
|
previewToken.host,
|
|
334
|
-
|
|
405
|
+
localPort,
|
|
406
|
+
localProtocol
|
|
335
407
|
);
|
|
336
408
|
stream.respond(responseHeaders);
|
|
337
409
|
request.pipe(stream, { end: true });
|
|
@@ -344,33 +416,50 @@ function createStreamHandler(
|
|
|
344
416
|
*/
|
|
345
417
|
export async function waitForPortToBeAvailable(
|
|
346
418
|
port: number,
|
|
347
|
-
options: { retryPeriod: number; timeout: number }
|
|
419
|
+
options: { retryPeriod: number; timeout: number; abortSignal: AbortSignal }
|
|
348
420
|
): Promise<void> {
|
|
349
421
|
return new Promise((resolve, reject) => {
|
|
422
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
423
|
+
options.abortSignal.addEventListener("abort", () => {
|
|
424
|
+
const abortError = new Error("waitForPortToBeAvailable() aborted");
|
|
425
|
+
(abortError as Error & { code: string }).code = "ABORT_ERR";
|
|
426
|
+
doReject(abortError);
|
|
427
|
+
});
|
|
428
|
+
|
|
350
429
|
const timeout = setTimeout(() => {
|
|
351
|
-
|
|
430
|
+
doReject(new Error(`Timed out waiting for port ${port}`));
|
|
352
431
|
}, options.timeout);
|
|
353
432
|
|
|
433
|
+
const interval = setInterval(checkPort, options.retryPeriod);
|
|
434
|
+
checkPort();
|
|
435
|
+
|
|
436
|
+
function doResolve() {
|
|
437
|
+
clearTimeout(timeout);
|
|
438
|
+
clearInterval(interval);
|
|
439
|
+
resolve();
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function doReject(err: unknown) {
|
|
443
|
+
clearInterval(interval);
|
|
444
|
+
clearTimeout(timeout);
|
|
445
|
+
reject(err);
|
|
446
|
+
}
|
|
447
|
+
|
|
354
448
|
function checkPort() {
|
|
355
449
|
// Testing whether a port is 'available' involves simply
|
|
356
450
|
// trying to make a server listen on that port, and retrying
|
|
357
451
|
// until it succeeds.
|
|
358
|
-
const server =
|
|
452
|
+
const server = createHttpServer();
|
|
359
453
|
server.on("error", (err) => {
|
|
360
454
|
// @ts-expect-error non standard property on Error
|
|
361
|
-
if (err.code
|
|
362
|
-
|
|
363
|
-
} else {
|
|
364
|
-
reject(err);
|
|
455
|
+
if (err.code !== "EADDRINUSE") {
|
|
456
|
+
doReject(err);
|
|
365
457
|
}
|
|
366
458
|
});
|
|
367
459
|
server.listen(port, () => {
|
|
368
460
|
server.close();
|
|
369
|
-
|
|
370
|
-
resolve();
|
|
461
|
+
doResolve();
|
|
371
462
|
});
|
|
372
463
|
}
|
|
373
|
-
|
|
374
|
-
checkPort();
|
|
375
464
|
});
|
|
376
465
|
}
|