wrangler 0.0.0-fb43821 → 0.0.0-fb53fda
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 +1 -1
- package/bin/wrangler.js +12 -3
- package/miniflare-dist/index.mjs +79 -0
- package/miniflare-dist/index.mjs.map +7 -0
- package/package.json +46 -17
- package/pages/functions/buildWorker.ts +62 -0
- package/pages/functions/filepath-routing.test.ts +223 -0
- package/pages/functions/filepath-routing.ts +181 -0
- package/pages/functions/identifiers.ts +78 -0
- package/pages/functions/routes.ts +151 -0
- package/pages/functions/template-worker.ts +130 -0
- package/src/__tests__/configuration.test.ts +2790 -0
- package/src/__tests__/dev.test.tsx +532 -0
- package/src/__tests__/guess-worker-format.test.ts +68 -0
- package/src/__tests__/{clipboardy-mock.js → helpers/clipboardy-mock.js} +0 -0
- package/src/__tests__/helpers/cmd-shim.d.ts +11 -0
- package/src/__tests__/helpers/faye-websocket.d.ts +6 -0
- package/src/__tests__/helpers/mock-account-id.ts +48 -0
- package/src/__tests__/helpers/mock-bin.ts +36 -0
- package/src/__tests__/helpers/mock-cfetch.ts +207 -0
- package/src/__tests__/helpers/mock-console.ts +70 -0
- package/src/__tests__/helpers/mock-dialogs.ts +65 -0
- package/src/__tests__/helpers/mock-kv.ts +33 -0
- package/src/__tests__/helpers/mock-stdin.ts +103 -0
- package/src/__tests__/helpers/mock-web-socket.ts +29 -0
- package/src/__tests__/helpers/run-in-tmp.ts +32 -0
- package/src/__tests__/helpers/run-wrangler.ts +16 -0
- package/src/__tests__/helpers/write-wrangler-toml.ts +17 -0
- package/src/__tests__/https-options.test.ts +127 -0
- package/src/__tests__/index.test.ts +770 -209
- package/src/__tests__/jest.setup.ts +69 -0
- package/src/__tests__/kv.test.ts +1380 -0
- package/src/__tests__/logout.test.ts +52 -0
- package/src/__tests__/package-manager.test.ts +206 -0
- package/src/__tests__/pages.test.ts +82 -0
- package/src/__tests__/parse.test.ts +322 -0
- package/src/__tests__/publish.test.ts +3431 -0
- package/src/__tests__/r2.test.ts +198 -0
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +425 -0
- package/src/__tests__/sentry.test.ts +146 -0
- package/src/__tests__/tail.test.ts +562 -0
- package/src/__tests__/whoami.test.tsx +100 -0
- package/src/bundle.ts +142 -0
- package/src/cfetch/index.ts +104 -0
- package/src/cfetch/internal.ts +139 -0
- package/src/cli.ts +16 -7
- package/src/config/README.md +107 -0
- package/src/config/config.ts +218 -0
- package/src/config/diagnostics.ts +80 -0
- package/src/config/environment.ts +366 -0
- package/src/config/index.ts +62 -0
- package/src/config/validation-helpers.ts +554 -0
- package/src/config/validation.ts +1191 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +63 -25
- package/src/create-worker-upload-form.ts +217 -0
- package/src/dev/dev.tsx +390 -0
- package/src/dev/local.tsx +232 -0
- package/src/dev/remote.tsx +203 -0
- package/src/dev/use-esbuild.ts +100 -0
- package/src/dialogs.tsx +4 -4
- package/src/entry.ts +237 -0
- package/src/environment-variables.ts +33 -0
- package/src/https-options.ts +122 -0
- package/src/index.tsx +1417 -915
- package/src/inspect.ts +617 -0
- package/src/intl-polyfill.d.ts +139 -0
- package/src/kv.ts +319 -0
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/enum-keys.ts +17 -0
- package/src/miniflare-cli/index.ts +37 -0
- package/src/module-collection.ts +229 -35
- package/src/open-in-browser.ts +25 -0
- package/src/package-manager.ts +126 -0
- package/src/pages.tsx +470 -227
- package/src/parse.ts +183 -0
- package/src/paths.ts +26 -0
- package/src/proxy.ts +440 -0
- package/src/publish.ts +292 -290
- package/src/r2.ts +50 -0
- package/src/reporting.ts +131 -0
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +224 -59
- package/src/tail/filters.ts +279 -0
- package/src/tail/index.ts +299 -0
- package/src/tail/printing.ts +62 -0
- package/src/user.tsx +301 -203
- package/src/whoami.tsx +69 -0
- package/src/worker.ts +163 -0
- package/templates/new-worker.js +15 -0
- package/templates/new-worker.ts +15 -0
- package/{static-asset-facade.js → templates/static-asset-facade.js} +0 -0
- package/templates/tsconfig.json +105 -0
- package/wrangler-dist/cli.js +134241 -116339
- package/wrangler-dist/cli.js.map +3 -3
- package/src/__tests__/mock-cfetch.js +0 -42
- package/src/api/form_data.ts +0 -141
- package/src/api/inspect.ts +0 -430
- package/src/api/worker.ts +0 -161
- package/src/cfetch.ts +0 -72
- package/src/config.ts +0 -122
- package/src/dev.tsx +0 -776
- package/src/kv.tsx +0 -211
- package/src/tail.tsx +0 -71
package/src/pages.tsx
CHANGED
|
@@ -1,24 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { existsSync, lstatSync, readFileSync } from "fs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import type { RequestInfo, RequestInit } from "undici";
|
|
9
|
-
import open from "open";
|
|
1
|
+
/* eslint-disable no-shadow */
|
|
2
|
+
|
|
3
|
+
import { execSync, spawn } from "node:child_process";
|
|
4
|
+
import { existsSync, lstatSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { URL } from "node:url";
|
|
10
8
|
import { watch } from "chokidar";
|
|
9
|
+
import { getType } from "mime";
|
|
10
|
+
import { buildWorker } from "../pages/functions/buildWorker";
|
|
11
|
+
import { generateConfigFromFileTree } from "../pages/functions/filepath-routing";
|
|
12
|
+
import { writeRoutesModule } from "../pages/functions/routes";
|
|
13
|
+
import openInBrowser from "./open-in-browser";
|
|
14
|
+
import { toUrlPath } from "./paths";
|
|
15
|
+
import type { Config } from "../pages/functions/routes";
|
|
16
|
+
import type { Headers, Request, fetch } from "@miniflare/core";
|
|
17
|
+
import type { BuildResult } from "esbuild";
|
|
18
|
+
import type { MiniflareOptions } from "miniflare";
|
|
19
|
+
import type { BuilderCallback } from "yargs";
|
|
20
|
+
|
|
21
|
+
// Defer importing miniflare until we really need it. This takes ~0.5s
|
|
22
|
+
// and also modifies some `stream/web` and `undici` prototypes, so we
|
|
23
|
+
// don't want to do this if pages commands aren't being called.
|
|
11
24
|
|
|
12
|
-
|
|
25
|
+
export const pagesBetaWarning =
|
|
26
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose";
|
|
13
27
|
|
|
14
|
-
const
|
|
28
|
+
const EXIT_CALLBACKS: (() => void)[] = [];
|
|
29
|
+
const EXIT = (message?: string, code?: number) => {
|
|
30
|
+
if (message) console.log(message);
|
|
31
|
+
if (code) process.exitCode = code;
|
|
32
|
+
EXIT_CALLBACKS.forEach((callback) => callback());
|
|
33
|
+
RUNNING_BUILDERS.forEach((builder) => builder.stop?.());
|
|
34
|
+
process.exit(code);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
process.on("SIGINT", () => EXIT());
|
|
38
|
+
process.on("SIGTERM", () => EXIT());
|
|
39
|
+
|
|
40
|
+
function isWindows() {
|
|
41
|
+
return process.platform === "win32";
|
|
42
|
+
}
|
|
15
43
|
|
|
16
44
|
const SECONDS_TO_WAIT_FOR_PROXY = 5;
|
|
17
45
|
|
|
18
|
-
|
|
46
|
+
async function sleep(ms: number) {
|
|
19
47
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
|
+
}
|
|
20
49
|
|
|
21
|
-
|
|
50
|
+
function getPids(pid: number) {
|
|
22
51
|
const pids: number[] = [pid];
|
|
23
52
|
let command: string, regExp: RegExp;
|
|
24
53
|
|
|
@@ -43,9 +72,9 @@ const getPids = (pid: number) => {
|
|
|
43
72
|
} catch {}
|
|
44
73
|
|
|
45
74
|
return pids;
|
|
46
|
-
}
|
|
75
|
+
}
|
|
47
76
|
|
|
48
|
-
|
|
77
|
+
function getPort(pid: number) {
|
|
49
78
|
let command: string, regExp: RegExp;
|
|
50
79
|
|
|
51
80
|
if (isWindows()) {
|
|
@@ -70,24 +99,19 @@ const getPort = (pid: number) => {
|
|
|
70
99
|
`Error scanning for ports of process with PID ${pid}: ${thrown}`
|
|
71
100
|
);
|
|
72
101
|
}
|
|
73
|
-
}
|
|
102
|
+
}
|
|
74
103
|
|
|
75
|
-
|
|
104
|
+
async function spawnProxyProcess({
|
|
76
105
|
port,
|
|
77
106
|
command,
|
|
78
107
|
}: {
|
|
79
108
|
port?: number;
|
|
80
109
|
command: (string | number)[];
|
|
81
|
-
})
|
|
82
|
-
const exit: Exit = (message) => {
|
|
83
|
-
if (message) console.error(message);
|
|
84
|
-
if (proxy) proxy.kill();
|
|
85
|
-
return undefined;
|
|
86
|
-
};
|
|
87
|
-
|
|
110
|
+
}): Promise<void | number> {
|
|
88
111
|
if (command.length === 0)
|
|
89
|
-
return
|
|
90
|
-
"Must specify a directory of static assets to serve or a command to run."
|
|
112
|
+
return EXIT(
|
|
113
|
+
"Must specify a directory of static assets to serve or a command to run.",
|
|
114
|
+
1
|
|
91
115
|
);
|
|
92
116
|
|
|
93
117
|
console.log(`Running ${command.join(" ")}...`);
|
|
@@ -102,6 +126,9 @@ const spawnProxyProcess = async ({
|
|
|
102
126
|
},
|
|
103
127
|
}
|
|
104
128
|
);
|
|
129
|
+
EXIT_CALLBACKS.push(() => {
|
|
130
|
+
proxy.kill();
|
|
131
|
+
});
|
|
105
132
|
|
|
106
133
|
proxy.stdout.on("data", (data) => {
|
|
107
134
|
console.log(`[proxy]: ${data}`);
|
|
@@ -130,34 +157,35 @@ const spawnProxyProcess = async ({
|
|
|
130
157
|
.filter((port) => port !== undefined)[0];
|
|
131
158
|
|
|
132
159
|
if (port === undefined) {
|
|
133
|
-
return
|
|
134
|
-
"Could not automatically determine proxy port. Please specify the proxy port with --proxy."
|
|
160
|
+
return EXIT(
|
|
161
|
+
"Could not automatically determine proxy port. Please specify the proxy port with --proxy.",
|
|
162
|
+
1
|
|
135
163
|
);
|
|
136
164
|
} else {
|
|
137
165
|
console.log(`Automatically determined the proxy port to be ${port}.`);
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
168
|
|
|
141
|
-
return
|
|
142
|
-
}
|
|
169
|
+
return port;
|
|
170
|
+
}
|
|
143
171
|
|
|
144
|
-
|
|
172
|
+
function escapeRegex(str: string) {
|
|
145
173
|
return str.replace(/[-/\\^$*+?.()|[]{}]/g, "\\$&");
|
|
146
|
-
}
|
|
174
|
+
}
|
|
147
175
|
|
|
148
|
-
|
|
176
|
+
type Replacements = Record<string, string>;
|
|
149
177
|
|
|
150
|
-
|
|
178
|
+
function replacer(str: string, replacements: Replacements) {
|
|
151
179
|
for (const [replacement, value] of Object.entries(replacements)) {
|
|
152
180
|
str = str.replace(`:${replacement}`, value);
|
|
153
181
|
}
|
|
154
182
|
return str;
|
|
155
|
-
}
|
|
183
|
+
}
|
|
156
184
|
|
|
157
|
-
|
|
185
|
+
function generateRulesMatcher<T>(
|
|
158
186
|
rules?: Record<string, T>,
|
|
159
187
|
replacer: (match: T, replacements: Replacements) => T = (match) => match
|
|
160
|
-
)
|
|
188
|
+
) {
|
|
161
189
|
// TODO: How can you test cross-host rules?
|
|
162
190
|
if (!rules) return () => [];
|
|
163
191
|
|
|
@@ -204,9 +232,9 @@ export const generateRulesMatcher = <T,>(
|
|
|
204
232
|
})
|
|
205
233
|
.filter((value) => value !== undefined) as T[];
|
|
206
234
|
};
|
|
207
|
-
}
|
|
235
|
+
}
|
|
208
236
|
|
|
209
|
-
|
|
237
|
+
function generateHeadersMatcher(headersFile: string) {
|
|
210
238
|
if (existsSync(headersFile)) {
|
|
211
239
|
const contents = readFileSync(headersFile).toString();
|
|
212
240
|
|
|
@@ -273,9 +301,9 @@ const generateHeadersMatcher = (headersFile: string) => {
|
|
|
273
301
|
} else {
|
|
274
302
|
return () => undefined;
|
|
275
303
|
}
|
|
276
|
-
}
|
|
304
|
+
}
|
|
277
305
|
|
|
278
|
-
|
|
306
|
+
function generateRedirectsMatcher(redirectsFile: string) {
|
|
279
307
|
if (existsSync(redirectsFile)) {
|
|
280
308
|
const contents = readFileSync(redirectsFile).toString();
|
|
281
309
|
|
|
@@ -322,26 +350,26 @@ const generateRedirectsMatcher = (redirectsFile: string) => {
|
|
|
322
350
|
} else {
|
|
323
351
|
return () => undefined;
|
|
324
352
|
}
|
|
325
|
-
}
|
|
353
|
+
}
|
|
326
354
|
|
|
327
|
-
|
|
355
|
+
function extractPathname(
|
|
328
356
|
path = "/",
|
|
329
357
|
includeSearch: boolean,
|
|
330
358
|
includeHash: boolean
|
|
331
|
-
)
|
|
359
|
+
) {
|
|
332
360
|
if (!path.startsWith("/")) path = `/${path}`;
|
|
333
361
|
const url = new URL(`//${path}`, "relative://");
|
|
334
362
|
return `${url.pathname}${includeSearch ? url.search : ""}${
|
|
335
363
|
includeHash ? url.hash : ""
|
|
336
364
|
}`;
|
|
337
|
-
}
|
|
365
|
+
}
|
|
338
366
|
|
|
339
|
-
|
|
367
|
+
function validateURL(
|
|
340
368
|
token: string,
|
|
341
369
|
onlyRelative = false,
|
|
342
370
|
includeSearch = false,
|
|
343
371
|
includeHash = false
|
|
344
|
-
)
|
|
372
|
+
) {
|
|
345
373
|
const host = /^https:\/\/+(?<host>[^/]+)\/?(?<path>.*)/.exec(token);
|
|
346
374
|
if (host && host.groups && host.groups.host) {
|
|
347
375
|
if (onlyRelative) return;
|
|
@@ -362,14 +390,16 @@ const validateURL = (
|
|
|
362
390
|
}
|
|
363
391
|
}
|
|
364
392
|
return "";
|
|
365
|
-
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function hasFileExtension(pathname: string) {
|
|
396
|
+
return /\/.+\.[a-z0-9]+$/i.test(pathname);
|
|
397
|
+
}
|
|
366
398
|
|
|
367
|
-
|
|
368
|
-
|
|
399
|
+
async function generateAssetsFetch(directory: string): Promise<typeof fetch> {
|
|
400
|
+
// Defer importing miniflare until we really need it
|
|
401
|
+
const { Headers, Request, Response } = await import("@miniflare/core");
|
|
369
402
|
|
|
370
|
-
const generateAssetsFetch = async (
|
|
371
|
-
directory: string
|
|
372
|
-
): Promise<typeof fetch> => {
|
|
373
403
|
const headersFile = join(directory, "_headers");
|
|
374
404
|
const redirectsFile = join(directory, "_redirects");
|
|
375
405
|
const workerFile = join(directory, "_worker.js");
|
|
@@ -466,12 +496,20 @@ const generateAssetsFetch = async (
|
|
|
466
496
|
if ((asset = getAsset(`${cwd}/404.html`))) {
|
|
467
497
|
deconstructedResponse.status = 404;
|
|
468
498
|
deconstructedResponse.body = serveAsset(asset);
|
|
499
|
+
deconstructedResponse.headers.set(
|
|
500
|
+
"Content-Type",
|
|
501
|
+
getType(asset) || "application/octet-stream"
|
|
502
|
+
);
|
|
469
503
|
return deconstructedResponse;
|
|
470
504
|
}
|
|
471
505
|
}
|
|
472
506
|
|
|
473
507
|
if ((asset = getAsset(`/index.html`))) {
|
|
474
508
|
deconstructedResponse.body = serveAsset(asset);
|
|
509
|
+
deconstructedResponse.headers.set(
|
|
510
|
+
"Content-Type",
|
|
511
|
+
getType(asset) || "application/octet-stream"
|
|
512
|
+
);
|
|
475
513
|
return deconstructedResponse;
|
|
476
514
|
}
|
|
477
515
|
|
|
@@ -484,6 +522,10 @@ const generateAssetsFetch = async (
|
|
|
484
522
|
if (url.pathname.endsWith("/")) {
|
|
485
523
|
if ((asset = getAsset(`${url.pathname}/index.html`))) {
|
|
486
524
|
deconstructedResponse.body = serveAsset(asset);
|
|
525
|
+
deconstructedResponse.headers.set(
|
|
526
|
+
"Content-Type",
|
|
527
|
+
getType(asset) || "application/octet-stream"
|
|
528
|
+
);
|
|
487
529
|
return deconstructedResponse;
|
|
488
530
|
} else if (
|
|
489
531
|
(asset = getAsset(`${url.pathname.replace(/\/$/, ".html")}`))
|
|
@@ -511,6 +553,10 @@ const generateAssetsFetch = async (
|
|
|
511
553
|
const extensionlessPath = url.pathname.slice(0, -".html".length);
|
|
512
554
|
if (getAsset(extensionlessPath) || extensionlessPath === "/") {
|
|
513
555
|
deconstructedResponse.body = serveAsset(asset);
|
|
556
|
+
deconstructedResponse.headers.set(
|
|
557
|
+
"Content-Type",
|
|
558
|
+
getType(asset) || "application/octet-stream"
|
|
559
|
+
);
|
|
514
560
|
return deconstructedResponse;
|
|
515
561
|
} else {
|
|
516
562
|
deconstructedResponse.status = 301;
|
|
@@ -522,6 +568,10 @@ const generateAssetsFetch = async (
|
|
|
522
568
|
}
|
|
523
569
|
} else {
|
|
524
570
|
deconstructedResponse.body = serveAsset(asset);
|
|
571
|
+
deconstructedResponse.headers.set(
|
|
572
|
+
"Content-Type",
|
|
573
|
+
getType(asset) || "application/octet-stream"
|
|
574
|
+
);
|
|
525
575
|
return deconstructedResponse;
|
|
526
576
|
}
|
|
527
577
|
} else if (hasFileExtension(url.pathname)) {
|
|
@@ -531,6 +581,10 @@ const generateAssetsFetch = async (
|
|
|
531
581
|
|
|
532
582
|
if ((asset = getAsset(`${url.pathname}.html`))) {
|
|
533
583
|
deconstructedResponse.body = serveAsset(asset);
|
|
584
|
+
deconstructedResponse.headers.set(
|
|
585
|
+
"Content-Type",
|
|
586
|
+
getType(asset) || "application/octet-stream"
|
|
587
|
+
);
|
|
534
588
|
return deconstructedResponse;
|
|
535
589
|
}
|
|
536
590
|
|
|
@@ -572,7 +626,7 @@ const generateAssetsFetch = async (
|
|
|
572
626
|
});
|
|
573
627
|
};
|
|
574
628
|
|
|
575
|
-
return
|
|
629
|
+
return async (input, init) => {
|
|
576
630
|
const request = new Request(input, init);
|
|
577
631
|
const deconstructedResponse = generateResponse(request);
|
|
578
632
|
attachHeaders(request, deconstructedResponse);
|
|
@@ -587,178 +641,284 @@ const generateAssetsFetch = async (
|
|
|
587
641
|
headers,
|
|
588
642
|
status: deconstructedResponse.status,
|
|
589
643
|
});
|
|
590
|
-
}
|
|
591
|
-
}
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const RUNNING_BUILDERS: BuildResult[] = [];
|
|
648
|
+
|
|
649
|
+
async function buildFunctions({
|
|
650
|
+
scriptPath,
|
|
651
|
+
outputConfigPath,
|
|
652
|
+
functionsDirectory,
|
|
653
|
+
minify = false,
|
|
654
|
+
sourcemap = false,
|
|
655
|
+
fallbackService = "ASSETS",
|
|
656
|
+
watch = false,
|
|
657
|
+
onEnd,
|
|
658
|
+
}: {
|
|
659
|
+
scriptPath: string;
|
|
660
|
+
outputConfigPath?: string;
|
|
661
|
+
functionsDirectory: string;
|
|
662
|
+
minify?: boolean;
|
|
663
|
+
sourcemap?: boolean;
|
|
664
|
+
fallbackService?: string;
|
|
665
|
+
watch?: boolean;
|
|
666
|
+
onEnd?: () => void;
|
|
667
|
+
}) {
|
|
668
|
+
RUNNING_BUILDERS.forEach(
|
|
669
|
+
(runningBuilder) => runningBuilder.stop && runningBuilder.stop()
|
|
670
|
+
);
|
|
592
671
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
"dev [directory] [-- command]",
|
|
596
|
-
"🧑💻 Develop your full-stack Pages application locally",
|
|
597
|
-
(yargs) => {
|
|
598
|
-
return yargs
|
|
599
|
-
.positional("directory", {
|
|
600
|
-
type: "string",
|
|
601
|
-
demandOption: undefined,
|
|
602
|
-
description: "The directory of static assets to serve",
|
|
603
|
-
})
|
|
604
|
-
.positional("command", {
|
|
605
|
-
type: "string",
|
|
606
|
-
demandOption: undefined,
|
|
607
|
-
description: "The proxy command to run",
|
|
608
|
-
})
|
|
609
|
-
.options({
|
|
610
|
-
local: {
|
|
611
|
-
type: "boolean",
|
|
612
|
-
default: true,
|
|
613
|
-
description: "Run on my machine",
|
|
614
|
-
},
|
|
615
|
-
port: {
|
|
616
|
-
type: "number",
|
|
617
|
-
default: 8788,
|
|
618
|
-
description: "The port to listen on (serve from)",
|
|
619
|
-
},
|
|
620
|
-
proxy: {
|
|
621
|
-
type: "number",
|
|
622
|
-
description:
|
|
623
|
-
"The port to proxy (where the static assets are served)",
|
|
624
|
-
},
|
|
625
|
-
"script-path": {
|
|
626
|
-
type: "string",
|
|
627
|
-
default: "_worker.js",
|
|
628
|
-
description:
|
|
629
|
-
"The location of the single Worker script if not using functions",
|
|
630
|
-
},
|
|
631
|
-
binding: {
|
|
632
|
-
type: "array",
|
|
633
|
-
description: "Bind variable/secret (KEY=VALUE)",
|
|
634
|
-
alias: "b",
|
|
635
|
-
},
|
|
636
|
-
kv: {
|
|
637
|
-
type: "array",
|
|
638
|
-
description: "KV namespace to bind",
|
|
639
|
-
alias: "k",
|
|
640
|
-
},
|
|
641
|
-
do: {
|
|
642
|
-
type: "array",
|
|
643
|
-
description: "Durable Object to bind (NAME=CLASS)",
|
|
644
|
-
alias: "o",
|
|
645
|
-
},
|
|
646
|
-
// TODO: Miniflare user options
|
|
647
|
-
});
|
|
648
|
-
},
|
|
649
|
-
async ({
|
|
650
|
-
local,
|
|
651
|
-
directory,
|
|
652
|
-
port,
|
|
653
|
-
proxy: requestedProxyPort,
|
|
654
|
-
"script-path": singleWorkerScriptPath,
|
|
655
|
-
binding: bindings = [],
|
|
656
|
-
kv: kvs = [],
|
|
657
|
-
do: durableObjects = [],
|
|
658
|
-
"--": remaining = [],
|
|
659
|
-
}) => {
|
|
660
|
-
if (!local) {
|
|
661
|
-
console.error("Only local mode is supported at the moment.");
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
672
|
+
const routesModule = join(tmpdir(), "./functionsRoutes.mjs");
|
|
673
|
+
const baseURL = toUrlPath("/");
|
|
664
674
|
|
|
665
|
-
|
|
666
|
-
|
|
675
|
+
const config: Config = await generateConfigFromFileTree({
|
|
676
|
+
baseDir: functionsDirectory,
|
|
677
|
+
baseURL,
|
|
678
|
+
});
|
|
667
679
|
|
|
668
|
-
|
|
680
|
+
if (outputConfigPath) {
|
|
681
|
+
writeFileSync(
|
|
682
|
+
outputConfigPath,
|
|
683
|
+
JSON.stringify({ ...config, baseURL }, null, 2)
|
|
684
|
+
);
|
|
685
|
+
}
|
|
669
686
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
687
|
+
await writeRoutesModule({
|
|
688
|
+
config,
|
|
689
|
+
srcDir: functionsDirectory,
|
|
690
|
+
outfile: routesModule,
|
|
691
|
+
});
|
|
675
692
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
693
|
+
RUNNING_BUILDERS.push(
|
|
694
|
+
await buildWorker({
|
|
695
|
+
routesModule,
|
|
696
|
+
outfile: scriptPath,
|
|
697
|
+
minify,
|
|
698
|
+
sourcemap,
|
|
699
|
+
fallbackService,
|
|
700
|
+
watch,
|
|
701
|
+
onEnd,
|
|
702
|
+
})
|
|
703
|
+
);
|
|
704
|
+
}
|
|
682
705
|
|
|
683
|
-
|
|
684
|
-
|
|
706
|
+
export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
707
|
+
return yargs
|
|
708
|
+
.command(
|
|
709
|
+
"dev [directory] [-- command]",
|
|
710
|
+
"🧑💻 Develop your full-stack Pages application locally",
|
|
711
|
+
(yargs) => {
|
|
712
|
+
return yargs
|
|
713
|
+
.positional("directory", {
|
|
714
|
+
type: "string",
|
|
715
|
+
demandOption: undefined,
|
|
716
|
+
description: "The directory of static assets to serve",
|
|
717
|
+
})
|
|
718
|
+
.positional("command", {
|
|
719
|
+
type: "string",
|
|
720
|
+
demandOption: undefined,
|
|
721
|
+
description: "The proxy command to run",
|
|
722
|
+
})
|
|
723
|
+
.options({
|
|
724
|
+
local: {
|
|
725
|
+
type: "boolean",
|
|
726
|
+
default: true,
|
|
727
|
+
description: "Run on my machine",
|
|
728
|
+
},
|
|
729
|
+
port: {
|
|
730
|
+
type: "number",
|
|
731
|
+
default: 8788,
|
|
732
|
+
description: "The port to listen on (serve from)",
|
|
733
|
+
},
|
|
734
|
+
proxy: {
|
|
735
|
+
type: "number",
|
|
736
|
+
description:
|
|
737
|
+
"The port to proxy (where the static assets are served)",
|
|
738
|
+
},
|
|
739
|
+
"script-path": {
|
|
740
|
+
type: "string",
|
|
741
|
+
default: "_worker.js",
|
|
742
|
+
description:
|
|
743
|
+
"The location of the single Worker script if not using functions",
|
|
744
|
+
},
|
|
745
|
+
binding: {
|
|
746
|
+
type: "array",
|
|
747
|
+
description: "Bind variable/secret (KEY=VALUE)",
|
|
748
|
+
alias: "b",
|
|
749
|
+
},
|
|
750
|
+
kv: {
|
|
751
|
+
type: "array",
|
|
752
|
+
description: "KV namespace to bind",
|
|
753
|
+
alias: "k",
|
|
754
|
+
},
|
|
755
|
+
do: {
|
|
756
|
+
type: "array",
|
|
757
|
+
description: "Durable Object to bind (NAME=CLASS)",
|
|
758
|
+
alias: "o",
|
|
759
|
+
},
|
|
760
|
+
"live-reload": {
|
|
761
|
+
type: "boolean",
|
|
762
|
+
default: false,
|
|
763
|
+
description: "Auto reload HTML pages when change is detected",
|
|
764
|
+
},
|
|
765
|
+
// TODO: Miniflare user options
|
|
766
|
+
})
|
|
767
|
+
.epilogue(pagesBetaWarning);
|
|
768
|
+
},
|
|
769
|
+
async ({
|
|
770
|
+
local,
|
|
771
|
+
directory,
|
|
772
|
+
port,
|
|
773
|
+
proxy: requestedProxyPort,
|
|
774
|
+
"script-path": singleWorkerScriptPath,
|
|
775
|
+
binding: bindings = [],
|
|
776
|
+
kv: kvs = [],
|
|
777
|
+
do: durableObjects = [],
|
|
778
|
+
"live-reload": liveReload,
|
|
779
|
+
_: [_pages, _dev, ...remaining],
|
|
780
|
+
}) => {
|
|
781
|
+
// Beta message for `wrangler pages <commands>` usage
|
|
782
|
+
console.log(pagesBetaWarning);
|
|
783
|
+
|
|
784
|
+
if (!local) {
|
|
785
|
+
console.error("Only local mode is supported at the moment.");
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
685
788
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
}
|
|
789
|
+
const functionsDirectory = "./functions";
|
|
790
|
+
const usingFunctions = existsSync(functionsDirectory);
|
|
689
791
|
|
|
690
|
-
|
|
792
|
+
const command = remaining as (string | number)[];
|
|
691
793
|
|
|
692
|
-
|
|
693
|
-
const scriptPath = join(tmpdir(), "./functionsWorker.js");
|
|
694
|
-
miniflareArgs = {
|
|
695
|
-
scriptPath,
|
|
696
|
-
buildWatchPaths: [functionsDirectory],
|
|
697
|
-
buildCommand: `npx @cloudflare/pages-functions-compiler build ${functionsDirectory} --outfile ${scriptPath}`,
|
|
698
|
-
};
|
|
699
|
-
} else {
|
|
700
|
-
const scriptPath =
|
|
701
|
-
directory !== undefined
|
|
702
|
-
? join(directory, singleWorkerScriptPath)
|
|
703
|
-
: singleWorkerScriptPath;
|
|
794
|
+
let proxyPort: number | void;
|
|
704
795
|
|
|
705
|
-
if (
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
796
|
+
if (directory === undefined) {
|
|
797
|
+
proxyPort = await spawnProxyProcess({
|
|
798
|
+
port: requestedProxyPort,
|
|
799
|
+
command,
|
|
800
|
+
});
|
|
801
|
+
if (proxyPort === undefined) return undefined;
|
|
709
802
|
}
|
|
710
803
|
|
|
711
|
-
miniflareArgs = {
|
|
712
|
-
scriptPath,
|
|
713
|
-
};
|
|
714
|
-
}
|
|
804
|
+
let miniflareArgs: MiniflareOptions = {};
|
|
715
805
|
|
|
716
|
-
|
|
717
|
-
|
|
806
|
+
let scriptReadyResolve: () => void;
|
|
807
|
+
const scriptReadyPromise = new Promise<void>(
|
|
808
|
+
(resolve) => (scriptReadyResolve = resolve)
|
|
809
|
+
);
|
|
718
810
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
console.log(
|
|
811
|
+
if (usingFunctions) {
|
|
812
|
+
const scriptPath = join(tmpdir(), "./functionsWorker.js");
|
|
813
|
+
|
|
814
|
+
console.log(`Compiling worker to "${scriptPath}"...`);
|
|
815
|
+
|
|
816
|
+
try {
|
|
817
|
+
await buildFunctions({
|
|
818
|
+
scriptPath,
|
|
819
|
+
functionsDirectory,
|
|
820
|
+
sourcemap: true,
|
|
821
|
+
watch: true,
|
|
822
|
+
onEnd: () => scriptReadyResolve(),
|
|
823
|
+
});
|
|
824
|
+
} catch {}
|
|
825
|
+
|
|
826
|
+
watch([functionsDirectory], {
|
|
827
|
+
persistent: true,
|
|
828
|
+
ignoreInitial: true,
|
|
829
|
+
}).on("all", async () => {
|
|
830
|
+
await buildFunctions({
|
|
831
|
+
scriptPath,
|
|
832
|
+
functionsDirectory,
|
|
833
|
+
sourcemap: true,
|
|
834
|
+
watch: true,
|
|
835
|
+
onEnd: () => scriptReadyResolve(),
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
miniflareArgs = {
|
|
840
|
+
scriptPath,
|
|
841
|
+
};
|
|
842
|
+
} else {
|
|
843
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
844
|
+
scriptReadyResolve!();
|
|
845
|
+
|
|
846
|
+
const scriptPath =
|
|
847
|
+
directory !== undefined
|
|
848
|
+
? join(directory, singleWorkerScriptPath)
|
|
849
|
+
: singleWorkerScriptPath;
|
|
850
|
+
|
|
851
|
+
if (existsSync(scriptPath)) {
|
|
852
|
+
miniflareArgs = {
|
|
853
|
+
scriptPath,
|
|
854
|
+
};
|
|
855
|
+
} else {
|
|
856
|
+
console.log("No functions. Shimming...");
|
|
857
|
+
miniflareArgs = {
|
|
858
|
+
// TODO: The fact that these request/response hacks are necessary is ridiculous.
|
|
859
|
+
// We need to eliminate them from env.ASSETS.fetch (not sure if just local or prod as well)
|
|
860
|
+
script: `
|
|
861
|
+
export default {
|
|
862
|
+
async fetch(request, env, context) {
|
|
863
|
+
const response = await env.ASSETS.fetch(request.url, request)
|
|
864
|
+
return new Response(response.body, response)
|
|
865
|
+
}
|
|
866
|
+
}`,
|
|
867
|
+
};
|
|
868
|
+
}
|
|
723
869
|
}
|
|
724
|
-
}
|
|
725
870
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
modules: true,
|
|
871
|
+
// Defer importing miniflare until we really need it
|
|
872
|
+
const { Miniflare, Log, LogLevel } = await import("miniflare");
|
|
873
|
+
const { Response, fetch } = await import("@miniflare/core");
|
|
730
874
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
875
|
+
// Wait for esbuild to finish building before starting Miniflare.
|
|
876
|
+
// This must be before the call to `new Miniflare`, as that will
|
|
877
|
+
// asynchronously start loading the script. `await startServer()`
|
|
878
|
+
// internally just waits for that promise to resolve.
|
|
879
|
+
await scriptReadyPromise;
|
|
734
880
|
|
|
735
|
-
|
|
881
|
+
// `assetsFetch()` will only be called if there is `proxyPort` defined.
|
|
882
|
+
// We only define `proxyPort`, above, when there is no `directory` defined.
|
|
883
|
+
const assetsFetch =
|
|
884
|
+
directory !== undefined
|
|
885
|
+
? await generateAssetsFetch(directory)
|
|
886
|
+
: invalidAssetsFetch;
|
|
736
887
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
),
|
|
888
|
+
const miniflare = new Miniflare({
|
|
889
|
+
port,
|
|
890
|
+
watch: true,
|
|
891
|
+
modules: true,
|
|
742
892
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
893
|
+
log: new Log(LogLevel.ERROR, { prefix: "pages" }),
|
|
894
|
+
logUnhandledRejections: true,
|
|
895
|
+
sourceMap: true,
|
|
896
|
+
|
|
897
|
+
kvNamespaces: kvs.map((kv) => kv.toString()),
|
|
898
|
+
|
|
899
|
+
durableObjects: Object.fromEntries(
|
|
900
|
+
durableObjects.map((durableObject) =>
|
|
901
|
+
durableObject.toString().split("=")
|
|
902
|
+
)
|
|
747
903
|
),
|
|
748
904
|
|
|
905
|
+
// User bindings
|
|
906
|
+
bindings: {
|
|
907
|
+
...Object.fromEntries(
|
|
908
|
+
bindings
|
|
909
|
+
.map((binding) => binding.toString().split("="))
|
|
910
|
+
.map(([key, ...values]) => [key, values.join("=")])
|
|
911
|
+
),
|
|
912
|
+
},
|
|
913
|
+
|
|
749
914
|
// env.ASSETS.fetch
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
input: RequestInfo,
|
|
753
|
-
init?: RequestInit | undefined
|
|
754
|
-
) => {
|
|
915
|
+
serviceBindings: {
|
|
916
|
+
async ASSETS(request: Request) {
|
|
755
917
|
if (proxyPort) {
|
|
756
918
|
try {
|
|
757
|
-
let request = new Request(input, init);
|
|
758
919
|
const url = new URL(request.url);
|
|
759
|
-
url.host = `
|
|
760
|
-
|
|
761
|
-
return await fetch(request.url, request);
|
|
920
|
+
url.host = `localhost:${proxyPort}`;
|
|
921
|
+
return await fetch(url, request);
|
|
762
922
|
} catch (thrown) {
|
|
763
923
|
console.error(`Could not proxy request: ${thrown}`);
|
|
764
924
|
|
|
@@ -770,9 +930,7 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
770
930
|
}
|
|
771
931
|
} else {
|
|
772
932
|
try {
|
|
773
|
-
return await (
|
|
774
|
-
await generateAssetsFetch(directory)
|
|
775
|
-
)(input as any, init as any);
|
|
933
|
+
return await assetsFetch(request);
|
|
776
934
|
} catch (thrown) {
|
|
777
935
|
console.error(`Could not serve static asset: ${thrown}`);
|
|
778
936
|
|
|
@@ -785,34 +943,119 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
|
|
|
785
943
|
}
|
|
786
944
|
},
|
|
787
945
|
},
|
|
788
|
-
},
|
|
789
946
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
947
|
+
kvPersist: true,
|
|
948
|
+
durableObjectsPersist: true,
|
|
949
|
+
cachePersist: true,
|
|
950
|
+
liveReload,
|
|
793
951
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
const server = await miniflare.startServer();
|
|
798
|
-
console.log(`Serving at http://127.0.0.1:${port}/`);
|
|
952
|
+
...miniflareArgs,
|
|
953
|
+
});
|
|
799
954
|
|
|
800
|
-
|
|
801
|
-
|
|
955
|
+
try {
|
|
956
|
+
// `startServer` might throw if user code contains errors
|
|
957
|
+
const server = await miniflare.startServer();
|
|
958
|
+
console.log(`Serving at http://localhost:${port}/`);
|
|
959
|
+
|
|
960
|
+
if (process.env.BROWSER !== "none") {
|
|
961
|
+
await openInBrowser(`http://localhost:${port}/`);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
if (directory !== undefined && liveReload) {
|
|
965
|
+
watch([directory], {
|
|
966
|
+
persistent: true,
|
|
967
|
+
ignoreInitial: true,
|
|
968
|
+
}).on("all", async () => {
|
|
969
|
+
await miniflare.reload();
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
EXIT_CALLBACKS.push(() => {
|
|
974
|
+
server.close();
|
|
975
|
+
miniflare.dispose().catch((err) => miniflare.log.error(err));
|
|
976
|
+
});
|
|
977
|
+
} catch (e) {
|
|
978
|
+
miniflare.log.error(e as Error);
|
|
979
|
+
EXIT("Could not start Miniflare.", 1);
|
|
980
|
+
}
|
|
802
981
|
}
|
|
982
|
+
)
|
|
983
|
+
.command("functions", false, (yargs) =>
|
|
984
|
+
// we hide this command from help output because
|
|
985
|
+
// it's not meant to be used directly right now
|
|
986
|
+
yargs.command(
|
|
987
|
+
"build [directory]",
|
|
988
|
+
"Compile a folder of Cloudflare Pages Functions into a single Worker",
|
|
989
|
+
(yargs) =>
|
|
990
|
+
yargs
|
|
991
|
+
.positional("directory", {
|
|
992
|
+
type: "string",
|
|
993
|
+
default: "functions",
|
|
994
|
+
description: "The directory of Pages Functions",
|
|
995
|
+
})
|
|
996
|
+
.options({
|
|
997
|
+
"script-path": {
|
|
998
|
+
type: "string",
|
|
999
|
+
default: "_worker.js",
|
|
1000
|
+
description: "The location of the output Worker script",
|
|
1001
|
+
},
|
|
1002
|
+
"output-config-path": {
|
|
1003
|
+
type: "string",
|
|
1004
|
+
description: "The location for the output config file",
|
|
1005
|
+
},
|
|
1006
|
+
minify: {
|
|
1007
|
+
type: "boolean",
|
|
1008
|
+
default: false,
|
|
1009
|
+
description: "Minify the output Worker script",
|
|
1010
|
+
},
|
|
1011
|
+
sourcemap: {
|
|
1012
|
+
type: "boolean",
|
|
1013
|
+
default: false,
|
|
1014
|
+
description:
|
|
1015
|
+
"Generate a sourcemap for the output Worker script",
|
|
1016
|
+
},
|
|
1017
|
+
"fallback-service": {
|
|
1018
|
+
type: "string",
|
|
1019
|
+
default: "ASSETS",
|
|
1020
|
+
description:
|
|
1021
|
+
"The service to fallback to at the end of the `next` chain. Setting to '' will fallback to the global `fetch`.",
|
|
1022
|
+
},
|
|
1023
|
+
watch: {
|
|
1024
|
+
type: "boolean",
|
|
1025
|
+
default: false,
|
|
1026
|
+
description:
|
|
1027
|
+
"Watch for changes to the functions and automatically rebuild the Worker script",
|
|
1028
|
+
},
|
|
1029
|
+
})
|
|
1030
|
+
.epilogue(pagesBetaWarning),
|
|
1031
|
+
async ({
|
|
1032
|
+
directory,
|
|
1033
|
+
"script-path": scriptPath,
|
|
1034
|
+
"output-config-path": outputConfigPath,
|
|
1035
|
+
minify,
|
|
1036
|
+
sourcemap,
|
|
1037
|
+
fallbackService,
|
|
1038
|
+
watch,
|
|
1039
|
+
}) => {
|
|
1040
|
+
// Beta message for `wrangler pages <commands>` usage
|
|
1041
|
+
console.log(pagesBetaWarning);
|
|
1042
|
+
|
|
1043
|
+
await buildFunctions({
|
|
1044
|
+
scriptPath,
|
|
1045
|
+
outputConfigPath,
|
|
1046
|
+
functionsDirectory: directory,
|
|
1047
|
+
minify,
|
|
1048
|
+
sourcemap,
|
|
1049
|
+
fallbackService,
|
|
1050
|
+
watch,
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
)
|
|
1054
|
+
);
|
|
1055
|
+
};
|
|
803
1056
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
console.error(err);
|
|
808
|
-
});
|
|
809
|
-
});
|
|
810
|
-
process.on("SIGTERM", () => {
|
|
811
|
-
server.close();
|
|
812
|
-
miniflare.dispose().catch((err) => {
|
|
813
|
-
console.error(err);
|
|
814
|
-
});
|
|
815
|
-
});
|
|
816
|
-
}
|
|
1057
|
+
const invalidAssetsFetch: typeof fetch = () => {
|
|
1058
|
+
throw new Error(
|
|
1059
|
+
"Trying to fetch assets directly when there is no `directory` option specified, and not in `local` mode."
|
|
817
1060
|
);
|
|
818
1061
|
};
|