wrangler 2.0.25 → 2.0.26
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/miniflare-dist/index.mjs +15 -3
- package/package.json +3 -3
- package/src/__tests__/helpers/mock-cfetch.ts +33 -0
- package/src/__tests__/init.test.ts +537 -359
- package/src/__tests__/jest.setup.ts +3 -0
- package/src/__tests__/pages.test.ts +14 -0
- package/src/__tests__/tail.test.ts +19 -3
- package/src/api/dev.ts +1 -0
- package/src/cfetch/internal.ts +39 -0
- package/src/dev/dev.tsx +4 -0
- package/src/dev.tsx +2 -2
- package/src/init.ts +111 -38
- package/src/miniflare-cli/assets.ts +8 -0
- package/src/miniflare-cli/index.ts +6 -3
- package/src/pages/build.tsx +41 -15
- package/src/pages/constants.ts +1 -0
- package/src/pages/dev.tsx +86 -24
- package/src/pages/errors.ts +22 -0
- package/src/pages/functions/routes-consolidation.test.ts +185 -1
- package/src/pages/functions/routes-consolidation.ts +46 -2
- package/src/pages/functions/routes-transformation.ts +0 -3
- package/src/pages/functions.tsx +96 -0
- package/src/pages/index.tsx +65 -55
- package/src/pages/publish.tsx +27 -16
- package/src/tail/filters.ts +3 -1
- package/src/tail/printing.ts +2 -0
- package/templates/pages-template-plugin.ts +16 -4
- package/templates/pages-template-worker.ts +16 -5
- package/templates/service-bindings-module-facade.js +10 -7
- package/templates/service-bindings-sw-facade.js +10 -7
- package/wrangler-dist/cli.d.ts +1 -0
- package/wrangler-dist/cli.js +1034 -738
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fetchMock from "jest-fetch-mock";
|
|
2
2
|
import {
|
|
3
|
+
fetchDashboardScript,
|
|
3
4
|
fetchInternal,
|
|
4
5
|
fetchKVGetValue,
|
|
5
6
|
fetchR2Objects,
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
} from "../cfetch/internal";
|
|
8
9
|
import { confirm, prompt } from "../dialogs";
|
|
9
10
|
import {
|
|
11
|
+
mockFetchDashScript,
|
|
10
12
|
mockFetchInternal,
|
|
11
13
|
mockFetchKVGetValue,
|
|
12
14
|
mockFetchR2Objects,
|
|
@@ -49,6 +51,7 @@ jest.mock("../cfetch/internal");
|
|
|
49
51
|
"https://api.cloudflare.com/client/v4"
|
|
50
52
|
);
|
|
51
53
|
(fetchR2Objects as jest.Mock).mockImplementation(mockFetchR2Objects);
|
|
54
|
+
(fetchDashboardScript as jest.Mock).mockImplementation(mockFetchDashScript);
|
|
52
55
|
|
|
53
56
|
jest.mock("../dialogs");
|
|
54
57
|
|
|
@@ -97,6 +97,20 @@ describe("pages", () => {
|
|
|
97
97
|
expect(std.out).toMatchInlineSnapshot(`
|
|
98
98
|
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
99
99
|
|
|
100
|
+
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
101
|
+
`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should display for pages:functions:optimize-routes", async () => {
|
|
105
|
+
await expect(
|
|
106
|
+
runWrangler(
|
|
107
|
+
'pages functions optimize-routes --routes-path="/build/_routes.json" --output-routes-path="/build/_optimized-routes.json"'
|
|
108
|
+
)
|
|
109
|
+
).rejects.toThrowError();
|
|
110
|
+
|
|
111
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
112
|
+
"🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
|
|
113
|
+
|
|
100
114
|
[32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose[0m"
|
|
101
115
|
`);
|
|
102
116
|
});
|
|
@@ -118,7 +118,7 @@ describe("tail", () => {
|
|
|
118
118
|
const api = mockWebsocketAPIs();
|
|
119
119
|
await runWrangler("tail test-worker --status error");
|
|
120
120
|
await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
|
|
121
|
-
{ outcome: ["exception", "exceededCpu", "unknown"] },
|
|
121
|
+
{ outcome: ["exception", "exceededCpu", "exceededMemory", "unknown"] },
|
|
122
122
|
]);
|
|
123
123
|
});
|
|
124
124
|
|
|
@@ -126,7 +126,15 @@ describe("tail", () => {
|
|
|
126
126
|
const api = mockWebsocketAPIs();
|
|
127
127
|
await runWrangler("tail test-worker --status error --status canceled");
|
|
128
128
|
await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
|
|
129
|
-
{
|
|
129
|
+
{
|
|
130
|
+
outcome: [
|
|
131
|
+
"exception",
|
|
132
|
+
"exceededCpu",
|
|
133
|
+
"exceededMemory",
|
|
134
|
+
"unknown",
|
|
135
|
+
"canceled",
|
|
136
|
+
],
|
|
137
|
+
},
|
|
130
138
|
]);
|
|
131
139
|
});
|
|
132
140
|
|
|
@@ -213,7 +221,15 @@ describe("tail", () => {
|
|
|
213
221
|
const expectedWebsocketMessage = {
|
|
214
222
|
filters: [
|
|
215
223
|
{ sampling_rate },
|
|
216
|
-
{
|
|
224
|
+
{
|
|
225
|
+
outcome: [
|
|
226
|
+
"ok",
|
|
227
|
+
"exception",
|
|
228
|
+
"exceededCpu",
|
|
229
|
+
"exceededMemory",
|
|
230
|
+
"unknown",
|
|
231
|
+
],
|
|
232
|
+
},
|
|
217
233
|
{ method },
|
|
218
234
|
{ header: { key: "X-HELLO", query: "world" } },
|
|
219
235
|
{ client_ip },
|
package/src/api/dev.ts
CHANGED
package/src/cfetch/internal.ts
CHANGED
|
@@ -179,3 +179,42 @@ export async function fetchR2Objects(
|
|
|
179
179
|
);
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* This is a wrapper STOPGAP for getting the script which returns a raw text response.
|
|
185
|
+
*/
|
|
186
|
+
export async function fetchDashboardScript(
|
|
187
|
+
resource: string,
|
|
188
|
+
bodyInit: RequestInit = {}
|
|
189
|
+
): Promise<string> {
|
|
190
|
+
await requireLoggedIn();
|
|
191
|
+
const auth = requireApiToken();
|
|
192
|
+
const headers = cloneHeaders(bodyInit.headers);
|
|
193
|
+
addAuthorizationHeaderIfUnspecified(headers, auth);
|
|
194
|
+
addUserAgent(headers);
|
|
195
|
+
|
|
196
|
+
const response = await fetch(`${getCloudflareAPIBaseURL()}${resource}`, {
|
|
197
|
+
...bodyInit,
|
|
198
|
+
headers,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (!response.ok || !response.body) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Failed to fetch ${resource} - ${response.status}: ${response.statusText});`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const usesModules = response.headers
|
|
208
|
+
.get("content-type")
|
|
209
|
+
?.startsWith("multipart");
|
|
210
|
+
|
|
211
|
+
if (usesModules) {
|
|
212
|
+
const file = await response.text();
|
|
213
|
+
|
|
214
|
+
// Follow up on issue in Undici about multipart/form-data support & replace the workaround: https://github.com/nodejs/undici/issues/974
|
|
215
|
+
// This should be using a builtin formData() parser pattern.
|
|
216
|
+
return file.split("\n").slice(4, -4).join("\n");
|
|
217
|
+
} else {
|
|
218
|
+
return response.text();
|
|
219
|
+
}
|
|
220
|
+
}
|
package/src/dev/dev.tsx
CHANGED
|
@@ -493,6 +493,10 @@ function useHotkeys(props: {
|
|
|
493
493
|
break;
|
|
494
494
|
// open browser
|
|
495
495
|
case "b": {
|
|
496
|
+
if (ip === "0.0.0.0") {
|
|
497
|
+
await openInBrowser(`${localProtocol}://127.0.0.1:${port}`);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
496
500
|
await openInBrowser(`${localProtocol}://${ip}:${port}`);
|
|
497
501
|
break;
|
|
498
502
|
}
|
package/src/dev.tsx
CHANGED
|
@@ -502,10 +502,10 @@ export async function startDev(args: StartDevOptions) {
|
|
|
502
502
|
isWorkersSite={Boolean(args.site || config.site)}
|
|
503
503
|
compatibilityDate={getDevCompatibilityDate(
|
|
504
504
|
config,
|
|
505
|
-
args
|
|
505
|
+
args.compatibilityDate
|
|
506
506
|
)}
|
|
507
507
|
compatibilityFlags={
|
|
508
|
-
args
|
|
508
|
+
args.compatibilityFlags || config.compatibility_flags
|
|
509
509
|
}
|
|
510
510
|
usageModel={config.usage_model}
|
|
511
511
|
bindings={bindings}
|
package/src/init.ts
CHANGED
|
@@ -5,12 +5,16 @@ import TOML from "@iarna/toml";
|
|
|
5
5
|
import { findUp } from "find-up";
|
|
6
6
|
import { version as wranglerVersion } from "../package.json";
|
|
7
7
|
|
|
8
|
+
import { fetchDashboardScript } from "./cfetch/internal";
|
|
9
|
+
import { readConfig } from "./config";
|
|
8
10
|
import { confirm, select } from "./dialogs";
|
|
9
11
|
import { initializeGit, isGitInstalled, isInsideGitRepo } from "./git-client";
|
|
10
12
|
import { logger } from "./logger";
|
|
11
13
|
import { getPackageManager } from "./package-manager";
|
|
12
14
|
import { parsePackageJSON, parseTOML, readFileSync } from "./parse";
|
|
15
|
+
import { requireAuth } from "./user";
|
|
13
16
|
import { CommandLineArgsError, printWranglerBanner } from "./index";
|
|
17
|
+
import type { ConfigPath } from "./index";
|
|
14
18
|
|
|
15
19
|
import type { Argv, ArgumentsCamelCase } from "yargs";
|
|
16
20
|
|
|
@@ -36,6 +40,12 @@ export async function initOptions(yargs: Argv) {
|
|
|
36
40
|
describe: 'Answer "yes" to any prompts for new projects',
|
|
37
41
|
type: "boolean",
|
|
38
42
|
alias: "y",
|
|
43
|
+
})
|
|
44
|
+
.option("from-dash", {
|
|
45
|
+
describe: "Download script from the dashboard for local development",
|
|
46
|
+
type: "string",
|
|
47
|
+
requiresArg: true,
|
|
48
|
+
hidden: true,
|
|
39
49
|
});
|
|
40
50
|
}
|
|
41
51
|
|
|
@@ -61,7 +71,11 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
|
|
|
61
71
|
const devDepsToInstall: string[] = [];
|
|
62
72
|
const instructions: string[] = [];
|
|
63
73
|
let shouldRunPackageManagerInstall = false;
|
|
64
|
-
const
|
|
74
|
+
const fromDashScriptName = args["from-dash"] as string;
|
|
75
|
+
const creationDirectory = path.resolve(
|
|
76
|
+
process.cwd(),
|
|
77
|
+
(args.name ? args.name : fromDashScriptName) ?? ""
|
|
78
|
+
);
|
|
65
79
|
|
|
66
80
|
if (args.site) {
|
|
67
81
|
const gitDirectory =
|
|
@@ -90,6 +104,7 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
|
|
|
90
104
|
|
|
91
105
|
// TODO: ask which directory to make the worker in (defaults to args.name)
|
|
92
106
|
// TODO: if args.name isn't provided, ask what to name the worker
|
|
107
|
+
// Note: `--from-dash` will be a fallback creationDir/Worker name if none is provided.
|
|
93
108
|
|
|
94
109
|
const wranglerTomlDestination = path.join(
|
|
95
110
|
creationDirectory,
|
|
@@ -98,12 +113,15 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
|
|
|
98
113
|
let justCreatedWranglerToml = false;
|
|
99
114
|
|
|
100
115
|
if (fs.existsSync(wranglerTomlDestination)) {
|
|
116
|
+
let shouldContinue = false;
|
|
101
117
|
logger.warn(
|
|
102
118
|
`${path.relative(process.cwd(), wranglerTomlDestination)} already exists!`
|
|
103
119
|
);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
if (!fromDashScriptName) {
|
|
121
|
+
shouldContinue = await confirm(
|
|
122
|
+
"Do you want to continue initializing this project?"
|
|
123
|
+
);
|
|
124
|
+
}
|
|
107
125
|
if (!shouldContinue) {
|
|
108
126
|
return;
|
|
109
127
|
}
|
|
@@ -438,27 +456,23 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
|
|
|
438
456
|
process.cwd(),
|
|
439
457
|
path.join(creationDirectory, "./src/index.ts")
|
|
440
458
|
);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
: await getNewWorkerType(newWorkerFilename);
|
|
445
|
-
|
|
446
|
-
if (newWorkerType !== "none") {
|
|
447
|
-
const template = getNewWorkerTemplate("ts", newWorkerType);
|
|
448
|
-
|
|
459
|
+
if (fromDashScriptName) {
|
|
460
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
461
|
+
const accountId = await requireAuth(config);
|
|
449
462
|
await mkdir(path.join(creationDirectory, "./src"), {
|
|
450
463
|
recursive: true,
|
|
451
464
|
});
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
465
|
+
|
|
466
|
+
const dashScript = await fetchDashboardScript(
|
|
467
|
+
`/accounts/${accountId}/workers/scripts/${fromDashScriptName}`,
|
|
468
|
+
{
|
|
469
|
+
method: "GET",
|
|
470
|
+
}
|
|
455
471
|
);
|
|
456
472
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
path.join(creationDirectory, "./src/index.ts")
|
|
461
|
-
)}`
|
|
473
|
+
await writeFile(
|
|
474
|
+
path.join(creationDirectory, "./src/index.ts"),
|
|
475
|
+
dashScript
|
|
462
476
|
);
|
|
463
477
|
|
|
464
478
|
await writePackageJsonScriptsAndUpdateWranglerToml(
|
|
@@ -466,8 +480,39 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
|
|
|
466
480
|
justCreatedWranglerToml,
|
|
467
481
|
pathToPackageJson,
|
|
468
482
|
"src/index.ts",
|
|
469
|
-
|
|
483
|
+
{}
|
|
470
484
|
);
|
|
485
|
+
} else {
|
|
486
|
+
const newWorkerType = yesFlag
|
|
487
|
+
? "fetch"
|
|
488
|
+
: await getNewWorkerType(newWorkerFilename);
|
|
489
|
+
|
|
490
|
+
if (newWorkerType !== "none") {
|
|
491
|
+
const template = getNewWorkerTemplate("ts", newWorkerType);
|
|
492
|
+
|
|
493
|
+
await mkdir(path.join(creationDirectory, "./src"), {
|
|
494
|
+
recursive: true,
|
|
495
|
+
});
|
|
496
|
+
await writeFile(
|
|
497
|
+
path.join(creationDirectory, "./src/index.ts"),
|
|
498
|
+
readFileSync(path.join(__dirname, `../templates/${template}`))
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
logger.log(
|
|
502
|
+
`✨ Created ${path.relative(
|
|
503
|
+
process.cwd(),
|
|
504
|
+
path.join(creationDirectory, "./src/index.ts")
|
|
505
|
+
)}`
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
await writePackageJsonScriptsAndUpdateWranglerToml(
|
|
509
|
+
shouldWritePackageJsonScripts,
|
|
510
|
+
justCreatedWranglerToml,
|
|
511
|
+
pathToPackageJson,
|
|
512
|
+
"src/index.ts",
|
|
513
|
+
getNewWorkerToml(newWorkerType)
|
|
514
|
+
);
|
|
515
|
+
}
|
|
471
516
|
}
|
|
472
517
|
}
|
|
473
518
|
} else {
|
|
@@ -477,35 +522,63 @@ export async function initHandler(args: ArgumentsCamelCase<InitArgs>) {
|
|
|
477
522
|
path.join(creationDirectory, "./src/index.js")
|
|
478
523
|
);
|
|
479
524
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
if (newWorkerType !== "none") {
|
|
485
|
-
const template = getNewWorkerTemplate("js", newWorkerType);
|
|
486
|
-
|
|
525
|
+
if (fromDashScriptName) {
|
|
526
|
+
const config = readConfig(args.config as ConfigPath, args);
|
|
527
|
+
const accountId = await requireAuth(config);
|
|
487
528
|
await mkdir(path.join(creationDirectory, "./src"), {
|
|
488
529
|
recursive: true,
|
|
489
530
|
});
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
531
|
+
|
|
532
|
+
const dashScript = await fetchDashboardScript(
|
|
533
|
+
`/accounts/${accountId}/workers/scripts/${fromDashScriptName}`,
|
|
534
|
+
{
|
|
535
|
+
method: "GET",
|
|
536
|
+
}
|
|
493
537
|
);
|
|
494
538
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
path.join(creationDirectory, "./src/index.js")
|
|
499
|
-
)}`
|
|
539
|
+
await writeFile(
|
|
540
|
+
path.join(creationDirectory, "./src/index.js"),
|
|
541
|
+
dashScript
|
|
500
542
|
);
|
|
501
543
|
|
|
502
544
|
await writePackageJsonScriptsAndUpdateWranglerToml(
|
|
503
545
|
shouldWritePackageJsonScripts,
|
|
504
546
|
justCreatedWranglerToml,
|
|
505
547
|
pathToPackageJson,
|
|
506
|
-
"src/index.
|
|
507
|
-
|
|
548
|
+
"src/index.ts",
|
|
549
|
+
{}
|
|
508
550
|
);
|
|
551
|
+
} else {
|
|
552
|
+
const newWorkerType = yesFlag
|
|
553
|
+
? "fetch"
|
|
554
|
+
: await getNewWorkerType(newWorkerFilename);
|
|
555
|
+
|
|
556
|
+
if (newWorkerType !== "none") {
|
|
557
|
+
const template = getNewWorkerTemplate("js", newWorkerType);
|
|
558
|
+
|
|
559
|
+
await mkdir(path.join(creationDirectory, "./src"), {
|
|
560
|
+
recursive: true,
|
|
561
|
+
});
|
|
562
|
+
await writeFile(
|
|
563
|
+
path.join(creationDirectory, "./src/index.js"),
|
|
564
|
+
readFileSync(path.join(__dirname, `../templates/${template}`))
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
logger.log(
|
|
568
|
+
`✨ Created ${path.relative(
|
|
569
|
+
process.cwd(),
|
|
570
|
+
path.join(creationDirectory, "./src/index.js")
|
|
571
|
+
)}`
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
await writePackageJsonScriptsAndUpdateWranglerToml(
|
|
575
|
+
shouldWritePackageJsonScripts,
|
|
576
|
+
justCreatedWranglerToml,
|
|
577
|
+
pathToPackageJson,
|
|
578
|
+
"src/index.js",
|
|
579
|
+
getNewWorkerToml(newWorkerType)
|
|
580
|
+
);
|
|
581
|
+
}
|
|
509
582
|
}
|
|
510
583
|
}
|
|
511
584
|
}
|
|
@@ -466,6 +466,14 @@ async function generateAssetsFetch(
|
|
|
466
466
|
return deconstructedResponse;
|
|
467
467
|
}
|
|
468
468
|
} else if (hasFileExtension(assetName)) {
|
|
469
|
+
if ((asset = getAsset(assetName + ".html"))) {
|
|
470
|
+
deconstructedResponse.body = serveAsset(asset);
|
|
471
|
+
deconstructedResponse.headers.set(
|
|
472
|
+
"Content-Type",
|
|
473
|
+
getType(asset) || "application/octet-stream"
|
|
474
|
+
);
|
|
475
|
+
return deconstructedResponse;
|
|
476
|
+
}
|
|
469
477
|
notFound();
|
|
470
478
|
return deconstructedResponse;
|
|
471
479
|
}
|
|
@@ -76,10 +76,13 @@ async function main() {
|
|
|
76
76
|
namespace.get = (id) => {
|
|
77
77
|
const stub = new DurableObjectStub(factory, id);
|
|
78
78
|
stub.fetch = (...reqArgs) => {
|
|
79
|
-
const
|
|
79
|
+
const requestFromArgs = new MiniflareRequest(...reqArgs);
|
|
80
|
+
const url = new URL(requestFromArgs.url);
|
|
81
|
+
url.host = host;
|
|
82
|
+
if (port !== undefined) url.port = port.toString();
|
|
80
83
|
const request = new MiniflareRequest(
|
|
81
|
-
url,
|
|
82
|
-
|
|
84
|
+
url.toString(),
|
|
85
|
+
requestFromArgs
|
|
83
86
|
);
|
|
84
87
|
request.headers.set("x-miniflare-durable-object-name", name);
|
|
85
88
|
request.headers.set("x-miniflare-durable-object-id", id.toString());
|
package/src/pages/build.tsx
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
+
import { FatalError } from "../errors";
|
|
4
5
|
import { logger } from "../logger";
|
|
5
6
|
import * as metrics from "../metrics";
|
|
6
7
|
import { toUrlPath } from "../paths";
|
|
7
8
|
import { isInPagesCI } from "./constants";
|
|
9
|
+
import {
|
|
10
|
+
EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR,
|
|
11
|
+
FunctionsNoRoutesError,
|
|
12
|
+
getFunctionsNoRoutesWarning,
|
|
13
|
+
} from "./errors";
|
|
8
14
|
import { buildPlugin } from "./functions/buildPlugin";
|
|
9
15
|
import { buildWorker } from "./functions/buildWorker";
|
|
10
16
|
import { generateConfigFromFileTree } from "./functions/filepath-routing";
|
|
@@ -104,23 +110,37 @@ export const Handler = async ({
|
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
buildOutputDirectory ??= dirname(outfile);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
try {
|
|
114
|
+
await buildFunctions({
|
|
115
|
+
outfile,
|
|
116
|
+
outputConfigPath,
|
|
117
|
+
functionsDirectory: directory,
|
|
118
|
+
minify,
|
|
119
|
+
sourcemap,
|
|
120
|
+
fallbackService,
|
|
121
|
+
watch,
|
|
122
|
+
plugin,
|
|
123
|
+
buildOutputDirectory,
|
|
124
|
+
nodeCompat,
|
|
125
|
+
routesOutputPath,
|
|
126
|
+
});
|
|
127
|
+
} catch (e) {
|
|
128
|
+
if (e instanceof FunctionsNoRoutesError) {
|
|
129
|
+
throw new FatalError(
|
|
130
|
+
getFunctionsNoRoutesWarning(directory),
|
|
131
|
+
EXIT_CODE_FUNCTIONS_NO_ROUTES_ERROR
|
|
132
|
+
);
|
|
133
|
+
} else {
|
|
134
|
+
throw e;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
121
137
|
await metrics.sendMetricsEvent("build pages functions");
|
|
122
138
|
};
|
|
123
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Builds a Functions worker based on the functions directory, with filepath and handler based routing.
|
|
142
|
+
* @throws FunctionsNoRoutesError when there are no routes found in the functions directory
|
|
143
|
+
*/
|
|
124
144
|
export async function buildFunctions({
|
|
125
145
|
outfile,
|
|
126
146
|
outputConfigPath,
|
|
@@ -164,7 +184,13 @@ export async function buildFunctions({
|
|
|
164
184
|
baseURL,
|
|
165
185
|
});
|
|
166
186
|
|
|
167
|
-
if (config.routes
|
|
187
|
+
if (!config.routes || config.routes.length === 0) {
|
|
188
|
+
throw new FunctionsNoRoutesError(
|
|
189
|
+
`Failed to find any routes while compiling Functions in: ${functionsDirectory}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (routesOutputPath) {
|
|
168
194
|
const routesJSON = convertRoutesToRoutesJSONSpec(config.routes);
|
|
169
195
|
writeFileSync(routesOutputPath, JSON.stringify(routesJSON, null, 2));
|
|
170
196
|
}
|
package/src/pages/constants.ts
CHANGED
|
@@ -8,4 +8,5 @@ export const SECONDS_TO_WAIT_FOR_PROXY = 5;
|
|
|
8
8
|
export const isInPagesCI = !!process.env.CF_PAGES;
|
|
9
9
|
/** The max number of rules in _routes.json */
|
|
10
10
|
export const MAX_FUNCTIONS_ROUTES_RULES = 100;
|
|
11
|
+
export const MAX_FUNCTIONS_ROUTES_RULE_LENGTH = 100;
|
|
11
12
|
export const ROUTES_SPEC_VERSION = 1;
|