wrangler 0.0.0-e3cab74 → 0.0.0-e3ce82b
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 +43 -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 +1713 -411
- package/src/__tests__/dev.test.tsx +954 -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 +67 -2
- 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 +138 -747
- package/src/__tests__/init.test.ts +1637 -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__/package-manager.test.ts +154 -7
- package/src/__tests__/pages.test.ts +754 -0
- package/src/__tests__/parse.test.ts +8 -0
- package/src/__tests__/publish.test.ts +4374 -1025
- 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 +60 -7
- package/src/abort.d.ts +3 -0
- package/src/bundle.ts +75 -11
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +29 -20
- 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 +237 -23
- package/src/config/validation.ts +722 -191
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +65 -27
- 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 +401 -0
- package/src/dev/local.tsx +322 -0
- package/src/dev/remote.tsx +237 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +64 -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 +1386 -867
- 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 +59 -11
- package/src/pages.tsx +1123 -75
- package/src/parse.ts +26 -6
- package/src/proxy.ts +159 -57
- package/src/publish.ts +581 -228
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +130 -45
- 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 +275 -110
- package/src/whoami.tsx +5 -3
- package/src/{api/worker.ts → worker.ts} +24 -29
- package/src/zones.ts +73 -0
- package/templates/gitignore +171 -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/static-asset-facade.js +1 -5
- package/wrangler-dist/cli.js +104803 -118375
- 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/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/wrangler-dist/cli.js.map +0 -7
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
|
|
|
@@ -75,9 +74,11 @@ type TomlError = Error & {
|
|
|
75
74
|
/**
|
|
76
75
|
* A wrapper around `TOML.parse` that throws a `ParseError`.
|
|
77
76
|
*/
|
|
78
|
-
export function parseTOML(input: string, file?: string):
|
|
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): object {
|
|
|
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) {
|
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,64 @@ 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({
|
|
104
|
+
server,
|
|
105
|
+
gracefulTerminationTimeout: 0,
|
|
106
|
+
}),
|
|
107
|
+
});
|
|
108
|
+
})
|
|
109
|
+
.catch(async (err) => {
|
|
110
|
+
logger.error("Failed to create proxy server:", err);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}, [proxy, localProtocol]);
|
|
74
114
|
|
|
75
115
|
/**
|
|
76
116
|
* When we're not connected / getting a fresh token on changes,
|
|
@@ -98,6 +138,10 @@ export function usePreviewServer({
|
|
|
98
138
|
}
|
|
99
139
|
|
|
100
140
|
useEffect(() => {
|
|
141
|
+
if (proxy === undefined) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
101
145
|
// If we don't have a token, that means either we're just starting up,
|
|
102
146
|
// or we're refreshing the token.
|
|
103
147
|
if (!previewToken) {
|
|
@@ -109,8 +153,8 @@ export function usePreviewServer({
|
|
|
109
153
|
// store the stream in a buffer so we can replay it later
|
|
110
154
|
streamBufferRef.current.push({ stream, headers });
|
|
111
155
|
};
|
|
112
|
-
proxy.on("stream", bufferStream);
|
|
113
|
-
cleanupListeners.push(() => proxy.off("stream", bufferStream));
|
|
156
|
+
proxy.server.on("stream", bufferStream);
|
|
157
|
+
cleanupListeners.push(() => proxy.server.off("stream", bufferStream));
|
|
114
158
|
|
|
115
159
|
const bufferRequestResponse = (
|
|
116
160
|
request: IncomingMessage,
|
|
@@ -120,8 +164,10 @@ export function usePreviewServer({
|
|
|
120
164
|
requestResponseBufferRef.current.push({ request, response });
|
|
121
165
|
};
|
|
122
166
|
|
|
123
|
-
proxy.on("request", bufferRequestResponse);
|
|
124
|
-
cleanupListeners.push(() =>
|
|
167
|
+
proxy.server.on("request", bufferRequestResponse);
|
|
168
|
+
cleanupListeners.push(() =>
|
|
169
|
+
proxy.server.off("request", bufferRequestResponse)
|
|
170
|
+
);
|
|
125
171
|
return () => {
|
|
126
172
|
cleanupListeners.forEach((cleanup) => cleanup());
|
|
127
173
|
};
|
|
@@ -142,9 +188,14 @@ export function usePreviewServer({
|
|
|
142
188
|
cleanupListeners.push(() => remote.off("close", retryServerSetup));
|
|
143
189
|
|
|
144
190
|
/** HTTP/2 -> HTTP/2 */
|
|
145
|
-
const handleStream = createStreamHandler(
|
|
146
|
-
|
|
147
|
-
|
|
191
|
+
const handleStream = createStreamHandler(
|
|
192
|
+
previewToken,
|
|
193
|
+
remote,
|
|
194
|
+
port,
|
|
195
|
+
localProtocol
|
|
196
|
+
);
|
|
197
|
+
proxy.server.on("stream", handleStream);
|
|
198
|
+
cleanupListeners.push(() => proxy.server.off("stream", handleStream));
|
|
148
199
|
|
|
149
200
|
// flush and replay buffered streams
|
|
150
201
|
streamBufferRef.current.forEach((buffer) =>
|
|
@@ -174,10 +225,15 @@ export function usePreviewServer({
|
|
|
174
225
|
const request = message.pipe(remote.request(headers));
|
|
175
226
|
request.on("response", (responseHeaders) => {
|
|
176
227
|
const status = responseHeaders[":status"] ?? 500;
|
|
228
|
+
|
|
229
|
+
// log all requests to terminal
|
|
230
|
+
logger.log(new Date().toLocaleTimeString(), method, url, status);
|
|
231
|
+
|
|
177
232
|
rewriteRemoteHostToLocalHostInHeaders(
|
|
178
233
|
responseHeaders,
|
|
179
234
|
previewToken.host,
|
|
180
|
-
port
|
|
235
|
+
port,
|
|
236
|
+
localProtocol
|
|
181
237
|
);
|
|
182
238
|
for (const name of Object.keys(responseHeaders)) {
|
|
183
239
|
if (name.startsWith(":")) {
|
|
@@ -195,8 +251,10 @@ export function usePreviewServer({
|
|
|
195
251
|
? createHandleAssetsRequest(assetPath, handleRequest)
|
|
196
252
|
: handleRequest;
|
|
197
253
|
|
|
198
|
-
proxy.on("request", actualHandleRequest);
|
|
199
|
-
cleanupListeners.push(() =>
|
|
254
|
+
proxy.server.on("request", actualHandleRequest);
|
|
255
|
+
cleanupListeners.push(() =>
|
|
256
|
+
proxy.server.off("request", actualHandleRequest)
|
|
257
|
+
);
|
|
200
258
|
|
|
201
259
|
// flush and replay buffered requests
|
|
202
260
|
requestResponseBufferRef.current.forEach(({ request, response }) =>
|
|
@@ -227,8 +285,8 @@ export function usePreviewServer({
|
|
|
227
285
|
remoteWebsocketClient.close();
|
|
228
286
|
});
|
|
229
287
|
};
|
|
230
|
-
proxy.on("upgrade", handleUpgrade);
|
|
231
|
-
cleanupListeners.push(() => proxy.off("upgrade", handleUpgrade));
|
|
288
|
+
proxy.server.on("upgrade", handleUpgrade);
|
|
289
|
+
cleanupListeners.push(() => proxy.server.off("upgrade", handleUpgrade));
|
|
232
290
|
|
|
233
291
|
return () => {
|
|
234
292
|
cleanupListeners.forEach((cleanup) => cleanup());
|
|
@@ -237,6 +295,7 @@ export function usePreviewServer({
|
|
|
237
295
|
previewToken,
|
|
238
296
|
publicRoot,
|
|
239
297
|
port,
|
|
298
|
+
localProtocol,
|
|
240
299
|
proxy,
|
|
241
300
|
// We use a state value as a sigil to trigger reconnecting the server.
|
|
242
301
|
// It's not used inside the effect, so react-hooks/exhaustive-deps
|
|
@@ -248,19 +307,37 @@ export function usePreviewServer({
|
|
|
248
307
|
// Start/stop the server whenever the
|
|
249
308
|
// containing component is mounted/unmounted.
|
|
250
309
|
useEffect(() => {
|
|
251
|
-
|
|
310
|
+
const abortController = new AbortController();
|
|
311
|
+
if (proxy === undefined) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
waitForPortToBeAvailable(port, {
|
|
316
|
+
retryPeriod: 200,
|
|
317
|
+
timeout: 2000,
|
|
318
|
+
abortSignal: abortController.signal,
|
|
319
|
+
})
|
|
252
320
|
.then(() => {
|
|
253
|
-
proxy.
|
|
254
|
-
|
|
321
|
+
proxy.server.on("listening", () => {
|
|
322
|
+
logger.log(`⬣ Listening at ${localProtocol}://${ip}:${port}`);
|
|
323
|
+
});
|
|
324
|
+
proxy.server.listen(port, ip);
|
|
255
325
|
})
|
|
256
326
|
.catch((err) => {
|
|
257
|
-
|
|
327
|
+
if ((err as { code: string }).code !== "ABORT_ERR") {
|
|
328
|
+
logger.error(`Failed to start server: ${err}`);
|
|
329
|
+
}
|
|
258
330
|
});
|
|
259
331
|
|
|
260
332
|
return () => {
|
|
261
|
-
|
|
333
|
+
abortController.abort();
|
|
334
|
+
// Running `proxy.server.close()` does not close open connections, preventing the process from exiting.
|
|
335
|
+
// So we use this `terminator` to close all the connections and force the server to shutdown.
|
|
336
|
+
proxy.terminator
|
|
337
|
+
.terminate()
|
|
338
|
+
.catch(() => logger.error("Failed to terminate the proxy server."));
|
|
262
339
|
};
|
|
263
|
-
}, [port, proxy]);
|
|
340
|
+
}, [port, ip, proxy, localProtocol]);
|
|
264
341
|
}
|
|
265
342
|
|
|
266
343
|
function createHandleAssetsRequest(
|
|
@@ -288,20 +365,18 @@ const HTTP1_HEADERS = new Set([
|
|
|
288
365
|
"http2-settings",
|
|
289
366
|
]);
|
|
290
367
|
|
|
291
|
-
function createProxyServer(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
);
|
|
301
|
-
})
|
|
368
|
+
async function createProxyServer(
|
|
369
|
+
localProtocol: "https" | "http"
|
|
370
|
+
): Promise<HttpServer | HttpsServer> {
|
|
371
|
+
const server: HttpServer | HttpsServer =
|
|
372
|
+
localProtocol === "https"
|
|
373
|
+
? createHttpsServer(await getHttpsOptions())
|
|
374
|
+
: createHttpServer();
|
|
375
|
+
|
|
376
|
+
return server
|
|
302
377
|
.on("upgrade", (req) => {
|
|
303
378
|
// log all websocket connections
|
|
304
|
-
|
|
379
|
+
logger.log(
|
|
305
380
|
new Date().toLocaleTimeString(),
|
|
306
381
|
req.method,
|
|
307
382
|
req.url,
|
|
@@ -311,14 +386,15 @@ function createProxyServer() {
|
|
|
311
386
|
})
|
|
312
387
|
.on("error", (err) => {
|
|
313
388
|
// log all connection errors
|
|
314
|
-
|
|
389
|
+
logger.error(new Date().toLocaleTimeString(), err);
|
|
315
390
|
});
|
|
316
391
|
}
|
|
317
392
|
|
|
318
393
|
function createStreamHandler(
|
|
319
394
|
previewToken: CfPreviewToken,
|
|
320
395
|
remote: ClientHttp2Session,
|
|
321
|
-
|
|
396
|
+
localPort: number,
|
|
397
|
+
localProtocol: "https" | "http"
|
|
322
398
|
) {
|
|
323
399
|
return function handleStream(
|
|
324
400
|
stream: ServerHttp2Stream,
|
|
@@ -331,7 +407,8 @@ function createStreamHandler(
|
|
|
331
407
|
rewriteRemoteHostToLocalHostInHeaders(
|
|
332
408
|
responseHeaders,
|
|
333
409
|
previewToken.host,
|
|
334
|
-
|
|
410
|
+
localPort,
|
|
411
|
+
localProtocol
|
|
335
412
|
);
|
|
336
413
|
stream.respond(responseHeaders);
|
|
337
414
|
request.pipe(stream, { end: true });
|
|
@@ -344,33 +421,58 @@ function createStreamHandler(
|
|
|
344
421
|
*/
|
|
345
422
|
export async function waitForPortToBeAvailable(
|
|
346
423
|
port: number,
|
|
347
|
-
options: { retryPeriod: number; timeout: number }
|
|
424
|
+
options: { retryPeriod: number; timeout: number; abortSignal: AbortSignal }
|
|
348
425
|
): Promise<void> {
|
|
349
426
|
return new Promise((resolve, reject) => {
|
|
427
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
428
|
+
options.abortSignal.addEventListener("abort", () => {
|
|
429
|
+
const abortError = new Error("waitForPortToBeAvailable() aborted");
|
|
430
|
+
(abortError as Error & { code: string }).code = "ABORT_ERR";
|
|
431
|
+
doReject(abortError);
|
|
432
|
+
});
|
|
433
|
+
|
|
350
434
|
const timeout = setTimeout(() => {
|
|
351
|
-
|
|
435
|
+
doReject(new Error(`Timed out waiting for port ${port}`));
|
|
352
436
|
}, options.timeout);
|
|
353
437
|
|
|
438
|
+
const interval = setInterval(checkPort, options.retryPeriod);
|
|
439
|
+
checkPort();
|
|
440
|
+
|
|
441
|
+
function doResolve() {
|
|
442
|
+
clearTimeout(timeout);
|
|
443
|
+
clearInterval(interval);
|
|
444
|
+
resolve();
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function doReject(err: unknown) {
|
|
448
|
+
clearInterval(interval);
|
|
449
|
+
clearTimeout(timeout);
|
|
450
|
+
reject(err);
|
|
451
|
+
}
|
|
452
|
+
|
|
354
453
|
function checkPort() {
|
|
355
454
|
// Testing whether a port is 'available' involves simply
|
|
356
455
|
// trying to make a server listen on that port, and retrying
|
|
357
456
|
// until it succeeds.
|
|
358
|
-
const server =
|
|
457
|
+
const server = createHttpServer();
|
|
458
|
+
const terminator = createHttpTerminator({
|
|
459
|
+
server,
|
|
460
|
+
gracefulTerminationTimeout: 0, // default 1000
|
|
461
|
+
});
|
|
462
|
+
|
|
359
463
|
server.on("error", (err) => {
|
|
360
464
|
// @ts-expect-error non standard property on Error
|
|
361
|
-
if (err.code
|
|
362
|
-
|
|
363
|
-
} else {
|
|
364
|
-
reject(err);
|
|
465
|
+
if (err.code !== "EADDRINUSE") {
|
|
466
|
+
doReject(err);
|
|
365
467
|
}
|
|
366
468
|
});
|
|
367
|
-
server.listen(port, () =>
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
469
|
+
server.listen(port, () =>
|
|
470
|
+
terminator
|
|
471
|
+
.terminate()
|
|
472
|
+
.then(doResolve, () =>
|
|
473
|
+
logger.error("Failed to terminate the port checker.")
|
|
474
|
+
)
|
|
475
|
+
);
|
|
372
476
|
}
|
|
373
|
-
|
|
374
|
-
checkPort();
|
|
375
477
|
});
|
|
376
478
|
}
|