wrangler 0.0.0-e88a54e → 0.0.0-e95e5a0
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 +25 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4828 -21
- package/package.json +29 -24
- package/pages/functions/buildPlugin.ts +92 -0
- package/pages/functions/buildWorker.ts +80 -4
- package/pages/functions/filepath-routing.test.ts +11 -0
- package/pages/functions/filepath-routing.ts +8 -0
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +146 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +530 -201
- package/src/__tests__/dev.test.tsx +284 -18
- package/src/__tests__/guess-worker-format.test.ts +28 -1
- package/src/__tests__/helpers/mock-cfetch.ts +5 -1
- package/src/__tests__/helpers/mock-console.ts +20 -3
- 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-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/run-in-tmp.ts +7 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +5 -2
- package/src/__tests__/index.test.ts +27 -769
- package/src/__tests__/init.test.ts +1516 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +133 -61
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +311 -26
- package/src/__tests__/publish.test.ts +2789 -618
- package/src/__tests__/r2.test.ts +26 -10
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +14 -9
- package/src/bundle.ts +30 -3
- package/src/cfetch/internal.ts +0 -2
- package/src/cli.ts +5 -11
- package/src/config/README.md +1 -1
- package/src/config/config.ts +20 -4
- package/src/config/environment.ts +32 -4
- package/src/config/index.ts +4 -3
- package/src/config/validation-helpers.ts +96 -7
- package/src/config/validation.ts +388 -54
- package/src/config-cache.ts +45 -0
- package/src/create-worker-preview.ts +22 -13
- package/src/create-worker-upload-form.ts +32 -9
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +132 -78
- package/src/dev/local.tsx +101 -21
- package/src/dev/remote.tsx +23 -13
- package/src/dev/use-esbuild.ts +23 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +83 -24
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +689 -394
- package/src/inspect.ts +17 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/index.ts +4 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +7 -7
- package/src/open-in-browser.ts +5 -4
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +875 -56
- package/src/parse.ts +1 -1
- package/src/proxy.ts +28 -19
- package/src/publish.ts +263 -141
- package/src/sites.tsx +27 -14
- 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 +116 -41
- package/src/whoami.tsx +2 -1
- package/src/worker.ts +15 -6
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +21162 -50227
- package/miniflare-dist/index.mjs.map +0 -7
- package/src/__tests__/dev2.test.tsx +0 -154
- package/src/__tests__/logout.test.ts +0 -52
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/reporting.ts +0 -131
- package/wrangler-dist/cli.js.map +0 -7
package/src/config/validation.ts
CHANGED
|
@@ -22,6 +22,9 @@ import {
|
|
|
22
22
|
all,
|
|
23
23
|
isMutuallyExclusiveWith,
|
|
24
24
|
inheritableInLegacyEnvironments,
|
|
25
|
+
appendEnvName,
|
|
26
|
+
getBindingNames,
|
|
27
|
+
isValidName,
|
|
25
28
|
} from "./validation-helpers";
|
|
26
29
|
import type { Config, DevConfig, RawConfig, RawDevConfig } from "./config";
|
|
27
30
|
import type {
|
|
@@ -32,6 +35,8 @@ import type {
|
|
|
32
35
|
} from "./environment";
|
|
33
36
|
import type { ValidatorFn } from "./validation-helpers";
|
|
34
37
|
|
|
38
|
+
const ENGLISH = new Intl.ListFormat("en");
|
|
39
|
+
|
|
35
40
|
/**
|
|
36
41
|
* Validate the given `rawConfig` object that was loaded from `configPath`.
|
|
37
42
|
*
|
|
@@ -43,7 +48,7 @@ import type { ValidatorFn } from "./validation-helpers";
|
|
|
43
48
|
export function normalizeAndValidateConfig(
|
|
44
49
|
rawConfig: RawConfig,
|
|
45
50
|
configPath: string | undefined,
|
|
46
|
-
|
|
51
|
+
args: unknown
|
|
47
52
|
): {
|
|
48
53
|
config: Config;
|
|
49
54
|
diagnostics: Diagnostics;
|
|
@@ -57,26 +62,28 @@ export function normalizeAndValidateConfig(
|
|
|
57
62
|
deprecated(
|
|
58
63
|
diagnostics,
|
|
59
64
|
rawConfig,
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
true
|
|
65
|
+
"miniflare",
|
|
66
|
+
"Wrangler does not use configuration in the `miniflare` section. Unless you are using Miniflare directly you can remove this section.",
|
|
67
|
+
true,
|
|
68
|
+
"😶 Ignored"
|
|
63
69
|
);
|
|
64
70
|
|
|
65
71
|
deprecated(
|
|
66
72
|
diagnostics,
|
|
67
73
|
rawConfig,
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
true
|
|
74
|
+
"type",
|
|
75
|
+
"Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build.",
|
|
76
|
+
true,
|
|
77
|
+
"😶 Ignored"
|
|
71
78
|
);
|
|
72
79
|
|
|
73
80
|
deprecated(
|
|
74
81
|
diagnostics,
|
|
75
82
|
rawConfig,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
"webpack_config",
|
|
84
|
+
"Most common features now work out of the box with wrangler, including modules, jsx, typescript, etc. If you need anything more, use a custom build.",
|
|
85
|
+
true,
|
|
86
|
+
"😶 Ignored"
|
|
80
87
|
);
|
|
81
88
|
|
|
82
89
|
validateOptionalProperty(
|
|
@@ -87,8 +94,34 @@ export function normalizeAndValidateConfig(
|
|
|
87
94
|
"boolean"
|
|
88
95
|
);
|
|
89
96
|
|
|
97
|
+
validateOptionalProperty(
|
|
98
|
+
diagnostics,
|
|
99
|
+
"",
|
|
100
|
+
"minify",
|
|
101
|
+
rawConfig.minify,
|
|
102
|
+
"boolean"
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
validateOptionalProperty(
|
|
106
|
+
diagnostics,
|
|
107
|
+
"",
|
|
108
|
+
"node_compat",
|
|
109
|
+
rawConfig.node_compat,
|
|
110
|
+
"boolean"
|
|
111
|
+
);
|
|
112
|
+
|
|
90
113
|
// TODO: set the default to false to turn on service environments as the default
|
|
91
|
-
const isLegacyEnv =
|
|
114
|
+
const isLegacyEnv =
|
|
115
|
+
(args as { "legacy-env": boolean | undefined })["legacy-env"] ??
|
|
116
|
+
rawConfig.legacy_env ??
|
|
117
|
+
true;
|
|
118
|
+
|
|
119
|
+
// TODO: remove this once service environments goes GA.
|
|
120
|
+
if (!isLegacyEnv) {
|
|
121
|
+
diagnostics.warnings.push(
|
|
122
|
+
"Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
|
|
123
|
+
);
|
|
124
|
+
}
|
|
92
125
|
|
|
93
126
|
const topLevelEnv = normalizeAndValidateEnvironment(
|
|
94
127
|
diagnostics,
|
|
@@ -96,13 +129,16 @@ export function normalizeAndValidateConfig(
|
|
|
96
129
|
rawConfig
|
|
97
130
|
);
|
|
98
131
|
|
|
132
|
+
//TODO: find a better way to define the type of Args that can be passed to the normalizeAndValidateConfig()
|
|
133
|
+
const envName = (args as { env: string | undefined }).env;
|
|
134
|
+
|
|
99
135
|
let activeEnv = topLevelEnv;
|
|
100
136
|
if (envName !== undefined) {
|
|
137
|
+
const envDiagnostics = new Diagnostics(
|
|
138
|
+
`"env.${envName}" environment configuration`
|
|
139
|
+
);
|
|
101
140
|
const rawEnv = rawConfig.env?.[envName];
|
|
102
141
|
if (rawEnv !== undefined) {
|
|
103
|
-
const envDiagnostics = new Diagnostics(
|
|
104
|
-
`"env.${envName}" environment configuration`
|
|
105
|
-
);
|
|
106
142
|
activeEnv = normalizeAndValidateEnvironment(
|
|
107
143
|
envDiagnostics,
|
|
108
144
|
configPath,
|
|
@@ -114,6 +150,18 @@ export function normalizeAndValidateConfig(
|
|
|
114
150
|
);
|
|
115
151
|
diagnostics.addChild(envDiagnostics);
|
|
116
152
|
} else {
|
|
153
|
+
// An environment was specified, but no configuration for it was found.
|
|
154
|
+
// To cover any legacy environment cases, where the `envName` is used,
|
|
155
|
+
// Let's create a fake active environment with the specified `envName`.
|
|
156
|
+
activeEnv = normalizeAndValidateEnvironment(
|
|
157
|
+
envDiagnostics,
|
|
158
|
+
configPath,
|
|
159
|
+
{},
|
|
160
|
+
envName,
|
|
161
|
+
topLevelEnv,
|
|
162
|
+
isLegacyEnv,
|
|
163
|
+
rawConfig
|
|
164
|
+
);
|
|
117
165
|
const envNames = rawConfig.env
|
|
118
166
|
? `The available configured environment names are: ${JSON.stringify(
|
|
119
167
|
Object.keys(rawConfig.env)
|
|
@@ -147,7 +195,12 @@ export function normalizeAndValidateConfig(
|
|
|
147
195
|
diagnostics,
|
|
148
196
|
rawConfig.migrations ?? []
|
|
149
197
|
),
|
|
150
|
-
site: normalizeAndValidateSite(
|
|
198
|
+
site: normalizeAndValidateSite(
|
|
199
|
+
diagnostics,
|
|
200
|
+
configPath,
|
|
201
|
+
rawConfig,
|
|
202
|
+
activeEnv.main
|
|
203
|
+
),
|
|
151
204
|
wasm_modules: normalizeAndValidateModulePaths(
|
|
152
205
|
diagnostics,
|
|
153
206
|
configPath,
|
|
@@ -160,13 +213,21 @@ export function normalizeAndValidateConfig(
|
|
|
160
213
|
"text_blobs",
|
|
161
214
|
rawConfig.text_blobs
|
|
162
215
|
),
|
|
216
|
+
data_blobs: normalizeAndValidateModulePaths(
|
|
217
|
+
diagnostics,
|
|
218
|
+
configPath,
|
|
219
|
+
"data_blobs",
|
|
220
|
+
rawConfig.data_blobs
|
|
221
|
+
),
|
|
163
222
|
};
|
|
164
223
|
|
|
224
|
+
validateBindingsHaveUniqueNames(diagnostics, config);
|
|
225
|
+
|
|
165
226
|
validateAdditionalProperties(
|
|
166
227
|
diagnostics,
|
|
167
228
|
"top-level",
|
|
168
229
|
Object.keys(rawConfig),
|
|
169
|
-
[...Object.keys(config), "env"
|
|
230
|
+
[...Object.keys(config), "env"]
|
|
170
231
|
);
|
|
171
232
|
|
|
172
233
|
return { config, diagnostics };
|
|
@@ -389,26 +450,91 @@ function normalizeAndValidateMigrations(
|
|
|
389
450
|
*/
|
|
390
451
|
function normalizeAndValidateSite(
|
|
391
452
|
diagnostics: Diagnostics,
|
|
392
|
-
|
|
453
|
+
configPath: string | undefined,
|
|
454
|
+
rawConfig: RawConfig,
|
|
455
|
+
mainEntryPoint: string | undefined
|
|
393
456
|
): Config["site"] {
|
|
394
|
-
if (
|
|
395
|
-
const { bucket, include = [], exclude = [], ...rest } =
|
|
396
|
-
|
|
457
|
+
if (rawConfig?.site !== undefined) {
|
|
458
|
+
const { bucket, include = [], exclude = [], ...rest } = rawConfig.site;
|
|
459
|
+
|
|
460
|
+
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), [
|
|
461
|
+
"entry-point",
|
|
462
|
+
]);
|
|
397
463
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
398
464
|
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
399
465
|
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
400
|
-
|
|
466
|
+
validateOptionalProperty(
|
|
467
|
+
diagnostics,
|
|
468
|
+
"site",
|
|
469
|
+
"entry-point",
|
|
470
|
+
rawConfig.site["entry-point"],
|
|
471
|
+
"string"
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
deprecated(
|
|
475
|
+
diagnostics,
|
|
476
|
+
rawConfig,
|
|
477
|
+
`site.entry-point`,
|
|
478
|
+
`Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:\n` +
|
|
479
|
+
`\`\`\`\n` +
|
|
480
|
+
`main = "${path.join(
|
|
481
|
+
String(rawConfig.site["entry-point"]) || "workers-site",
|
|
482
|
+
path.extname(String(rawConfig.site["entry-point"]) || "workers-site")
|
|
483
|
+
? ""
|
|
484
|
+
: "index.js"
|
|
485
|
+
)}"\n` +
|
|
486
|
+
`\`\`\``,
|
|
487
|
+
false,
|
|
488
|
+
undefined,
|
|
489
|
+
"warning"
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
let siteEntryPoint = rawConfig.site["entry-point"];
|
|
493
|
+
|
|
494
|
+
if (!mainEntryPoint && !siteEntryPoint) {
|
|
495
|
+
// this means that we're defaulting to "workers-site"
|
|
496
|
+
// so let's add the deprecation warning
|
|
497
|
+
diagnostics.warnings.push(
|
|
498
|
+
`Because you've defined a [site] configuration, we're defaulting to "workers-site" for the deprecated \`site.entry-point\`field.\n` +
|
|
499
|
+
`Add the top level \`main\` field to your configuration file:\n` +
|
|
500
|
+
`\`\`\`\n` +
|
|
501
|
+
`main = "workers-site/index.js"\n` +
|
|
502
|
+
`\`\`\``
|
|
503
|
+
);
|
|
504
|
+
siteEntryPoint = "workers-site";
|
|
505
|
+
} else if (mainEntryPoint && siteEntryPoint) {
|
|
506
|
+
diagnostics.errors.push(
|
|
507
|
+
`Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.\n` +
|
|
508
|
+
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
509
|
+
`Delete the deprecated \`site.entry-point\` field from your config.`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (configPath && siteEntryPoint) {
|
|
514
|
+
// rewrite the path to be relative to the working directory
|
|
515
|
+
siteEntryPoint = path.relative(
|
|
516
|
+
process.cwd(),
|
|
517
|
+
path.join(path.dirname(configPath), siteEntryPoint)
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
bucket,
|
|
523
|
+
"entry-point": siteEntryPoint,
|
|
524
|
+
include,
|
|
525
|
+
exclude,
|
|
526
|
+
};
|
|
401
527
|
}
|
|
402
528
|
return undefined;
|
|
403
529
|
}
|
|
404
530
|
|
|
405
531
|
/**
|
|
406
|
-
* Map the paths of the `wasm_modules` or `
|
|
532
|
+
* Map the paths of the `wasm_modules`, `text_blobs` or `data_blobs` configuration to be relative to the current working directory.
|
|
407
533
|
*/
|
|
408
534
|
function normalizeAndValidateModulePaths(
|
|
409
535
|
diagnostics: Diagnostics,
|
|
410
536
|
configPath: string | undefined,
|
|
411
|
-
field: "wasm_modules" | "text_blobs",
|
|
537
|
+
field: "wasm_modules" | "text_blobs" | "data_blobs",
|
|
412
538
|
rawMapping: Record<string, string> | undefined
|
|
413
539
|
): Record<string, string> | undefined {
|
|
414
540
|
if (rawMapping === undefined) {
|
|
@@ -431,6 +557,102 @@ function normalizeAndValidateModulePaths(
|
|
|
431
557
|
return mapping;
|
|
432
558
|
}
|
|
433
559
|
|
|
560
|
+
/**
|
|
561
|
+
* Check whether a value has the shape of a route, which can be a string
|
|
562
|
+
* or an object that looks like {pattern: string, zone_id: string }
|
|
563
|
+
*/
|
|
564
|
+
function isValidRouteValue(item: unknown): boolean {
|
|
565
|
+
return (
|
|
566
|
+
!!item &&
|
|
567
|
+
(typeof item === "string" ||
|
|
568
|
+
(typeof item === "object" &&
|
|
569
|
+
hasProperty(item, "pattern") &&
|
|
570
|
+
typeof item.pattern === "string" &&
|
|
571
|
+
// it could have a zone_name
|
|
572
|
+
((hasProperty(item, "zone_name") &&
|
|
573
|
+
typeof item.zone_name === "string") ||
|
|
574
|
+
// or a zone_id
|
|
575
|
+
(hasProperty(item, "zone_id") && typeof item.zone_id === "string")) &&
|
|
576
|
+
Object.keys(item).length === 2))
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Validate that the field is a route.
|
|
582
|
+
*/
|
|
583
|
+
const isRoute: ValidatorFn = (diagnostics, field, value) => {
|
|
584
|
+
if (value !== undefined && !isValidRouteValue(value)) {
|
|
585
|
+
diagnostics.errors.push(
|
|
586
|
+
`Expected "${field}" to be either a string, or an object with shape { pattern, zone_id | zone_name }, but got ${JSON.stringify(
|
|
587
|
+
value
|
|
588
|
+
)}.`
|
|
589
|
+
);
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
return true;
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Validate that the field is an array of routes.
|
|
597
|
+
*/
|
|
598
|
+
const isRouteArray: ValidatorFn = (diagnostics, field, value) => {
|
|
599
|
+
if (value === undefined) {
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
if (!Array.isArray(value)) {
|
|
603
|
+
diagnostics.errors.push(
|
|
604
|
+
`Expected "${field}" to be an array but got ${JSON.stringify(value)}.`
|
|
605
|
+
);
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
const invalidRoutes = [];
|
|
609
|
+
for (const item of value) {
|
|
610
|
+
if (!isValidRouteValue(item)) {
|
|
611
|
+
invalidRoutes.push(item);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (invalidRoutes.length > 0) {
|
|
615
|
+
diagnostics.errors.push(
|
|
616
|
+
`Expected "${field}" to be an array of either strings or objects with the shape { pattern, zone_id | zone_name }, but these weren't valid: ${JSON.stringify(
|
|
617
|
+
invalidRoutes,
|
|
618
|
+
null,
|
|
619
|
+
2
|
|
620
|
+
)}.`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
return invalidRoutes.length === 0;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
function validateRoute(
|
|
627
|
+
diagnostics: Diagnostics,
|
|
628
|
+
topLevelEnv: Environment | undefined,
|
|
629
|
+
rawEnv: RawEnvironment
|
|
630
|
+
): Config["route"] {
|
|
631
|
+
return inheritable(
|
|
632
|
+
diagnostics,
|
|
633
|
+
topLevelEnv,
|
|
634
|
+
rawEnv,
|
|
635
|
+
"route",
|
|
636
|
+
isRoute,
|
|
637
|
+
undefined
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function validateRoutes(
|
|
642
|
+
diagnostics: Diagnostics,
|
|
643
|
+
topLevelEnv: Environment | undefined,
|
|
644
|
+
rawEnv: RawEnvironment
|
|
645
|
+
): Config["routes"] {
|
|
646
|
+
return inheritable(
|
|
647
|
+
diagnostics,
|
|
648
|
+
topLevelEnv,
|
|
649
|
+
rawEnv,
|
|
650
|
+
"routes",
|
|
651
|
+
all(isRouteArray, isMutuallyExclusiveWith(rawEnv, "route")),
|
|
652
|
+
undefined
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
|
|
434
656
|
/**
|
|
435
657
|
* Validate top-level environment configuration and return the normalized values.
|
|
436
658
|
*/
|
|
@@ -496,29 +718,17 @@ function normalizeAndValidateEnvironment(
|
|
|
496
718
|
|
|
497
719
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
498
720
|
|
|
499
|
-
const route =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
"route",
|
|
504
|
-
isString,
|
|
505
|
-
undefined
|
|
506
|
-
);
|
|
507
|
-
const routes = inheritable(
|
|
508
|
-
diagnostics,
|
|
509
|
-
topLevelEnv,
|
|
510
|
-
rawEnv,
|
|
511
|
-
"routes",
|
|
512
|
-
all(isStringArray, isMutuallyExclusiveWith(rawEnv, "route")),
|
|
513
|
-
undefined
|
|
514
|
-
);
|
|
721
|
+
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
722
|
+
|
|
723
|
+
const routes = validateRoutes(diagnostics, topLevelEnv, rawEnv);
|
|
724
|
+
|
|
515
725
|
const workers_dev = inheritable(
|
|
516
726
|
diagnostics,
|
|
517
727
|
topLevelEnv,
|
|
518
728
|
rawEnv,
|
|
519
729
|
"workers_dev",
|
|
520
730
|
isBoolean,
|
|
521
|
-
|
|
731
|
+
undefined
|
|
522
732
|
);
|
|
523
733
|
|
|
524
734
|
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
@@ -530,12 +740,14 @@ function normalizeAndValidateEnvironment(
|
|
|
530
740
|
|
|
531
741
|
const environment: Environment = {
|
|
532
742
|
// Inherited fields
|
|
533
|
-
account_id:
|
|
743
|
+
account_id: inheritableInLegacyEnvironments(
|
|
534
744
|
diagnostics,
|
|
745
|
+
isLegacyEnv,
|
|
535
746
|
topLevelEnv,
|
|
536
747
|
rawEnv,
|
|
537
748
|
"account_id",
|
|
538
749
|
isString,
|
|
750
|
+
undefined,
|
|
539
751
|
undefined
|
|
540
752
|
),
|
|
541
753
|
compatibility_date: inheritable(
|
|
@@ -570,6 +782,12 @@ function normalizeAndValidateEnvironment(
|
|
|
570
782
|
isString,
|
|
571
783
|
"React.Fragment"
|
|
572
784
|
),
|
|
785
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
786
|
+
diagnostics,
|
|
787
|
+
topLevelEnv,
|
|
788
|
+
rawEnv,
|
|
789
|
+
configPath
|
|
790
|
+
),
|
|
573
791
|
rules: validateAndNormalizeRules(
|
|
574
792
|
diagnostics,
|
|
575
793
|
topLevelEnv,
|
|
@@ -583,7 +801,8 @@ function normalizeAndValidateEnvironment(
|
|
|
583
801
|
topLevelEnv,
|
|
584
802
|
rawEnv,
|
|
585
803
|
"name",
|
|
586
|
-
|
|
804
|
+
isValidName,
|
|
805
|
+
appendEnvName(envName),
|
|
587
806
|
undefined
|
|
588
807
|
),
|
|
589
808
|
main: normalizeAndValidateMainField(
|
|
@@ -674,11 +893,36 @@ function normalizeAndValidateEnvironment(
|
|
|
674
893
|
}
|
|
675
894
|
),
|
|
676
895
|
zone_id: rawEnv.zone_id,
|
|
896
|
+
minify: rawEnv.minify,
|
|
897
|
+
node_compat: rawEnv.node_compat,
|
|
677
898
|
};
|
|
678
899
|
|
|
679
900
|
return environment;
|
|
680
901
|
}
|
|
681
902
|
|
|
903
|
+
function validateAndNormalizeTsconfig(
|
|
904
|
+
diagnostics: Diagnostics,
|
|
905
|
+
topLevelEnv: Environment | undefined,
|
|
906
|
+
rawEnv: RawEnvironment,
|
|
907
|
+
configPath: string | undefined
|
|
908
|
+
) {
|
|
909
|
+
const tsconfig = inheritable(
|
|
910
|
+
diagnostics,
|
|
911
|
+
topLevelEnv,
|
|
912
|
+
rawEnv,
|
|
913
|
+
"tsconfig",
|
|
914
|
+
isString,
|
|
915
|
+
undefined
|
|
916
|
+
);
|
|
917
|
+
|
|
918
|
+
return configPath && tsconfig
|
|
919
|
+
? path.relative(
|
|
920
|
+
process.cwd(),
|
|
921
|
+
path.join(path.dirname(configPath), tsconfig)
|
|
922
|
+
)
|
|
923
|
+
: tsconfig;
|
|
924
|
+
}
|
|
925
|
+
|
|
682
926
|
const validateAndNormalizeRules = (
|
|
683
927
|
diagnostics: Diagnostics,
|
|
684
928
|
topLevelEnv: Environment | undefined,
|
|
@@ -694,7 +938,7 @@ const validateAndNormalizeRules = (
|
|
|
694
938
|
);
|
|
695
939
|
} else if (deprecatedRules) {
|
|
696
940
|
diagnostics.warnings.push(
|
|
697
|
-
`
|
|
941
|
+
`Deprecation: The \`build.upload.rules\` config field is no longer used, the rules should be specified via the \`rules\` config field. Delete the \`build.upload\` field from the configuration file, and add this:\n` +
|
|
698
942
|
"```\n" +
|
|
699
943
|
TOML.stringify({ rules: deprecatedRules }) +
|
|
700
944
|
"```"
|
|
@@ -867,7 +1111,7 @@ const validateBindingsProperty =
|
|
|
867
1111
|
diagnostics.warnings.push(
|
|
868
1112
|
`The following bindings are at the top level, but not on "env.${envName}".\n` +
|
|
869
1113
|
`This is not what you probably want, since "${field}" configuration is not inherited by environments.\n` +
|
|
870
|
-
`Please add a binding for each to "${fieldPath}.bindings"
|
|
1114
|
+
`Please add a binding for each to "${fieldPath}.bindings":\n` +
|
|
871
1115
|
missingBindings.map((name) => `- ${name}`).join("\n")
|
|
872
1116
|
);
|
|
873
1117
|
}
|
|
@@ -876,14 +1120,6 @@ const validateBindingsProperty =
|
|
|
876
1120
|
return isValid;
|
|
877
1121
|
};
|
|
878
1122
|
|
|
879
|
-
/**
|
|
880
|
-
* Get the names of the bindings collection in `value`.
|
|
881
|
-
*/
|
|
882
|
-
const getBindingNames = (value: unknown): string[] =>
|
|
883
|
-
((value as { bindings: { name: string }[] })?.bindings ?? []).map(
|
|
884
|
-
(binding) => binding.name
|
|
885
|
-
);
|
|
886
|
-
|
|
887
1123
|
/**
|
|
888
1124
|
* Check that the given field is a valid "durable_object" binding object.
|
|
889
1125
|
*/
|
|
@@ -1054,7 +1290,7 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1054
1290
|
const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
1055
1291
|
if (typeof value !== "object" || value === null) {
|
|
1056
1292
|
diagnostics.errors.push(
|
|
1057
|
-
`"
|
|
1293
|
+
`"r2_buckets" bindings should be objects, but got ${JSON.stringify(
|
|
1058
1294
|
value
|
|
1059
1295
|
)}`
|
|
1060
1296
|
);
|
|
@@ -1088,3 +1324,101 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1088
1324
|
}
|
|
1089
1325
|
return isValid;
|
|
1090
1326
|
};
|
|
1327
|
+
|
|
1328
|
+
/**
|
|
1329
|
+
* Check that bindings whose names might conflict, don't.
|
|
1330
|
+
*
|
|
1331
|
+
* We don't want to have, for example, a KV namespace named "DATA"
|
|
1332
|
+
* and a Durable Object also named "DATA". Then it would be ambiguous
|
|
1333
|
+
* what exactly would live at `env.DATA` (or in the case of service-workers,
|
|
1334
|
+
* the `DATA` global).
|
|
1335
|
+
*/
|
|
1336
|
+
const validateBindingsHaveUniqueNames = (
|
|
1337
|
+
diagnostics: Diagnostics,
|
|
1338
|
+
{
|
|
1339
|
+
durable_objects,
|
|
1340
|
+
kv_namespaces,
|
|
1341
|
+
r2_buckets,
|
|
1342
|
+
text_blobs,
|
|
1343
|
+
unsafe,
|
|
1344
|
+
vars,
|
|
1345
|
+
wasm_modules,
|
|
1346
|
+
data_blobs,
|
|
1347
|
+
}: Partial<Config>
|
|
1348
|
+
): boolean => {
|
|
1349
|
+
let hasDuplicates = false;
|
|
1350
|
+
|
|
1351
|
+
const bindingsGroupedByType = {
|
|
1352
|
+
"Durable Object": getBindingNames(durable_objects),
|
|
1353
|
+
"KV Namespace": getBindingNames(kv_namespaces),
|
|
1354
|
+
"R2 Bucket": getBindingNames(r2_buckets),
|
|
1355
|
+
"Text Blob": getBindingNames(text_blobs),
|
|
1356
|
+
Unsafe: getBindingNames(unsafe),
|
|
1357
|
+
"Environment Variable": getBindingNames(vars),
|
|
1358
|
+
"WASM Module": getBindingNames(wasm_modules),
|
|
1359
|
+
"Data Blob": getBindingNames(data_blobs),
|
|
1360
|
+
} as Record<string, string[]>;
|
|
1361
|
+
|
|
1362
|
+
const bindingsGroupedByName: Record<string, string[]> = {};
|
|
1363
|
+
|
|
1364
|
+
for (const bindingType in bindingsGroupedByType) {
|
|
1365
|
+
const bindingNames = bindingsGroupedByType[bindingType];
|
|
1366
|
+
|
|
1367
|
+
for (const bindingName of bindingNames) {
|
|
1368
|
+
if (!(bindingName in bindingsGroupedByName)) {
|
|
1369
|
+
bindingsGroupedByName[bindingName] = [];
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
bindingsGroupedByName[bindingName].push(bindingType);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
for (const bindingName in bindingsGroupedByName) {
|
|
1377
|
+
const bindingTypes = bindingsGroupedByName[bindingName];
|
|
1378
|
+
if (bindingTypes.length < 2) {
|
|
1379
|
+
// there's only one (or zero) binding(s) with this name, which is fine, actually
|
|
1380
|
+
continue;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
hasDuplicates = true;
|
|
1384
|
+
|
|
1385
|
+
// there's two types of duplicates we want to look for:
|
|
1386
|
+
// - bindings with the same name of the same type (e.g. two Durable Objects both named "OBJ")
|
|
1387
|
+
// - bindings with the same name of different types (a KV namespace and DO both named "DATA")
|
|
1388
|
+
|
|
1389
|
+
const sameType = bindingTypes
|
|
1390
|
+
// filter once to find duplicate binding types
|
|
1391
|
+
.filter((type, i) => bindingTypes.indexOf(type) !== i)
|
|
1392
|
+
// filter twice to only get _unique_ duplicate binding types
|
|
1393
|
+
.filter(
|
|
1394
|
+
(type, i, duplicateBindingTypes) =>
|
|
1395
|
+
duplicateBindingTypes.indexOf(type) === i
|
|
1396
|
+
);
|
|
1397
|
+
|
|
1398
|
+
const differentTypes = bindingTypes.filter(
|
|
1399
|
+
(type, i) => bindingTypes.indexOf(type) === i
|
|
1400
|
+
);
|
|
1401
|
+
|
|
1402
|
+
if (differentTypes.length > 1) {
|
|
1403
|
+
// we have multiple different types using the same name
|
|
1404
|
+
diagnostics.errors.push(
|
|
1405
|
+
`${bindingName} assigned to ${ENGLISH.format(differentTypes)} bindings.`
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
sameType.forEach((bindingType) => {
|
|
1410
|
+
diagnostics.errors.push(
|
|
1411
|
+
`${bindingName} assigned to multiple ${bindingType} bindings.`
|
|
1412
|
+
);
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
if (hasDuplicates) {
|
|
1417
|
+
const problem =
|
|
1418
|
+
"Bindings must have unique names, so that they can all be referenced in the worker.";
|
|
1419
|
+
const resolution = "Please change your bindings to have unique names.";
|
|
1420
|
+
diagnostics.errors.push(`${problem}\n${resolution}`);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
return !hasDuplicates;
|
|
1424
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
2
|
+
import { dirname, join } from "path";
|
|
3
|
+
|
|
4
|
+
let cacheMessageShown = false;
|
|
5
|
+
|
|
6
|
+
const cacheFolder = "node_modules/.cache/wrangler";
|
|
7
|
+
|
|
8
|
+
const showCacheMessage = () => {
|
|
9
|
+
if (!cacheMessageShown) {
|
|
10
|
+
console.log(
|
|
11
|
+
`Using cached values in '${cacheFolder}'. This is used as a temporary store to improve the developer experience for some commands. It may be purged at any time. It doesn't contain any sensitive information, but it should not be commited into source control.`
|
|
12
|
+
);
|
|
13
|
+
cacheMessageShown = true;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getConfigCache = <T>(fileName: string): Partial<T> => {
|
|
18
|
+
try {
|
|
19
|
+
const configCacheLocation = join(cacheFolder, fileName);
|
|
20
|
+
const configCache = JSON.parse(readFileSync(configCacheLocation, "utf-8"));
|
|
21
|
+
showCacheMessage();
|
|
22
|
+
return configCache;
|
|
23
|
+
} catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const saveToConfigCache = <T>(
|
|
29
|
+
fileName: string,
|
|
30
|
+
newValues: Partial<T>
|
|
31
|
+
) => {
|
|
32
|
+
const configCacheLocation = join(cacheFolder, fileName);
|
|
33
|
+
const existingValues = getConfigCache(fileName);
|
|
34
|
+
|
|
35
|
+
mkdirSync(dirname(configCacheLocation), { recursive: true });
|
|
36
|
+
writeFileSync(
|
|
37
|
+
configCacheLocation,
|
|
38
|
+
JSON.stringify({ ...existingValues, ...newValues }, null, 2)
|
|
39
|
+
);
|
|
40
|
+
showCacheMessage();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const purgeConfigCaches = () => {
|
|
44
|
+
rmSync(cacheFolder, { recursive: true, force: true });
|
|
45
|
+
};
|