wrangler 0.0.0-e29a241 → 0.0.0-e2f9bb2
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 +692 -321
- 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 +24 -0
- 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 +1042 -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 +13 -53
- package/src/config/environment.ts +88 -4
- package/src/config/index.ts +11 -4
- package/src/config/validation-helpers.ts +96 -7
- package/src/config/validation.ts +407 -79
- 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 +115 -29
- 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 +619 -377
- 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 +883 -62
- package/src/parse.ts +1 -1
- package/src/proxy.ts +25 -11
- 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 +21167 -50229
- 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,17 +22,21 @@ import {
|
|
|
22
22
|
all,
|
|
23
23
|
isMutuallyExclusiveWith,
|
|
24
24
|
inheritableInLegacyEnvironments,
|
|
25
|
+
appendEnvName,
|
|
26
|
+
getBindingNames,
|
|
27
|
+
isValidName,
|
|
25
28
|
} from "./validation-helpers";
|
|
29
|
+
import type { Config, DevConfig, RawConfig, RawDevConfig } from "./config";
|
|
26
30
|
import type {
|
|
27
|
-
|
|
31
|
+
RawEnvironment,
|
|
28
32
|
DeprecatedUpload,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from "./config";
|
|
33
|
-
import type { RawEnvironment, Environment, Rule } from "./environment";
|
|
33
|
+
Environment,
|
|
34
|
+
Rule,
|
|
35
|
+
} from "./environment";
|
|
34
36
|
import type { ValidatorFn } from "./validation-helpers";
|
|
35
37
|
|
|
38
|
+
const ENGLISH = new Intl.ListFormat("en");
|
|
39
|
+
|
|
36
40
|
/**
|
|
37
41
|
* Validate the given `rawConfig` object that was loaded from `configPath`.
|
|
38
42
|
*
|
|
@@ -44,7 +48,7 @@ import type { ValidatorFn } from "./validation-helpers";
|
|
|
44
48
|
export function normalizeAndValidateConfig(
|
|
45
49
|
rawConfig: RawConfig,
|
|
46
50
|
configPath: string | undefined,
|
|
47
|
-
|
|
51
|
+
args: unknown
|
|
48
52
|
): {
|
|
49
53
|
config: Config;
|
|
50
54
|
diagnostics: Diagnostics;
|
|
@@ -58,65 +62,87 @@ export function normalizeAndValidateConfig(
|
|
|
58
62
|
deprecated(
|
|
59
63
|
diagnostics,
|
|
60
64
|
rawConfig,
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
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"
|
|
64
69
|
);
|
|
65
70
|
|
|
66
71
|
deprecated(
|
|
67
72
|
diagnostics,
|
|
68
73
|
rawConfig,
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
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"
|
|
72
78
|
);
|
|
73
79
|
|
|
74
80
|
deprecated(
|
|
75
81
|
diagnostics,
|
|
76
82
|
rawConfig,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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"
|
|
81
87
|
);
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
validateOptionalProperty(
|
|
84
90
|
diagnostics,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
"",
|
|
92
|
+
"legacy_env",
|
|
93
|
+
rawConfig.legacy_env,
|
|
94
|
+
"boolean"
|
|
88
95
|
);
|
|
89
96
|
|
|
90
97
|
validateOptionalProperty(
|
|
91
98
|
diagnostics,
|
|
92
99
|
"",
|
|
93
|
-
"
|
|
94
|
-
rawConfig.
|
|
100
|
+
"minify",
|
|
101
|
+
rawConfig.minify,
|
|
102
|
+
"boolean"
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
validateOptionalProperty(
|
|
106
|
+
diagnostics,
|
|
107
|
+
"",
|
|
108
|
+
"node_compat",
|
|
109
|
+
rawConfig.node_compat,
|
|
95
110
|
"boolean"
|
|
96
111
|
);
|
|
97
112
|
|
|
98
113
|
// TODO: set the default to false to turn on service environments as the default
|
|
99
|
-
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
|
+
}
|
|
100
125
|
|
|
101
126
|
const topLevelEnv = normalizeAndValidateEnvironment(
|
|
102
127
|
diagnostics,
|
|
103
128
|
configPath,
|
|
104
|
-
rawConfig
|
|
105
|
-
deprecatedUpload
|
|
129
|
+
rawConfig
|
|
106
130
|
);
|
|
107
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
|
+
|
|
108
135
|
let activeEnv = topLevelEnv;
|
|
109
136
|
if (envName !== undefined) {
|
|
137
|
+
const envDiagnostics = new Diagnostics(
|
|
138
|
+
`"env.${envName}" environment configuration`
|
|
139
|
+
);
|
|
110
140
|
const rawEnv = rawConfig.env?.[envName];
|
|
111
141
|
if (rawEnv !== undefined) {
|
|
112
|
-
const envDiagnostics = new Diagnostics(
|
|
113
|
-
`"env.${envName}" environment configuration`
|
|
114
|
-
);
|
|
115
142
|
activeEnv = normalizeAndValidateEnvironment(
|
|
116
143
|
envDiagnostics,
|
|
117
144
|
configPath,
|
|
118
145
|
rawEnv,
|
|
119
|
-
deprecatedUpload,
|
|
120
146
|
envName,
|
|
121
147
|
topLevelEnv,
|
|
122
148
|
isLegacyEnv,
|
|
@@ -124,6 +150,18 @@ export function normalizeAndValidateConfig(
|
|
|
124
150
|
);
|
|
125
151
|
diagnostics.addChild(envDiagnostics);
|
|
126
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
|
+
);
|
|
127
165
|
const envNames = rawConfig.env
|
|
128
166
|
? `The available configured environment names are: ${JSON.stringify(
|
|
129
167
|
Object.keys(rawConfig.env)
|
|
@@ -157,7 +195,12 @@ export function normalizeAndValidateConfig(
|
|
|
157
195
|
diagnostics,
|
|
158
196
|
rawConfig.migrations ?? []
|
|
159
197
|
),
|
|
160
|
-
site: normalizeAndValidateSite(
|
|
198
|
+
site: normalizeAndValidateSite(
|
|
199
|
+
diagnostics,
|
|
200
|
+
configPath,
|
|
201
|
+
rawConfig,
|
|
202
|
+
activeEnv.main
|
|
203
|
+
),
|
|
161
204
|
wasm_modules: normalizeAndValidateModulePaths(
|
|
162
205
|
diagnostics,
|
|
163
206
|
configPath,
|
|
@@ -170,14 +213,21 @@ export function normalizeAndValidateConfig(
|
|
|
170
213
|
"text_blobs",
|
|
171
214
|
rawConfig.text_blobs
|
|
172
215
|
),
|
|
173
|
-
|
|
216
|
+
data_blobs: normalizeAndValidateModulePaths(
|
|
217
|
+
diagnostics,
|
|
218
|
+
configPath,
|
|
219
|
+
"data_blobs",
|
|
220
|
+
rawConfig.data_blobs
|
|
221
|
+
),
|
|
174
222
|
};
|
|
175
223
|
|
|
224
|
+
validateBindingsHaveUniqueNames(diagnostics, config);
|
|
225
|
+
|
|
176
226
|
validateAdditionalProperties(
|
|
177
227
|
diagnostics,
|
|
178
228
|
"top-level",
|
|
179
229
|
Object.keys(rawConfig),
|
|
180
|
-
[...Object.keys(config), "env"
|
|
230
|
+
[...Object.keys(config), "env"]
|
|
181
231
|
);
|
|
182
232
|
|
|
183
233
|
return { config, diagnostics };
|
|
@@ -188,7 +238,7 @@ export function normalizeAndValidateConfig(
|
|
|
188
238
|
*/
|
|
189
239
|
function normalizeAndValidateBuild(
|
|
190
240
|
diagnostics: Diagnostics,
|
|
191
|
-
|
|
241
|
+
rawEnv: RawEnvironment,
|
|
192
242
|
rawBuild: Config["build"],
|
|
193
243
|
configPath: string | undefined
|
|
194
244
|
): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
|
|
@@ -208,13 +258,13 @@ function normalizeAndValidateBuild(
|
|
|
208
258
|
|
|
209
259
|
deprecated(
|
|
210
260
|
diagnostics,
|
|
211
|
-
|
|
261
|
+
rawEnv,
|
|
212
262
|
"build.upload.format",
|
|
213
263
|
"The format is inferred automatically from the code.",
|
|
214
264
|
true
|
|
215
265
|
);
|
|
216
266
|
|
|
217
|
-
if (
|
|
267
|
+
if (rawEnv.main !== undefined && rawBuild.upload?.main) {
|
|
218
268
|
diagnostics.errors.push(
|
|
219
269
|
`Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.\n` +
|
|
220
270
|
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
@@ -223,7 +273,7 @@ function normalizeAndValidateBuild(
|
|
|
223
273
|
} else {
|
|
224
274
|
deprecated(
|
|
225
275
|
diagnostics,
|
|
226
|
-
|
|
276
|
+
rawEnv,
|
|
227
277
|
"build.upload.main",
|
|
228
278
|
`Delete the \`build.upload.main\` and \`build.upload.dir\` fields.\n` +
|
|
229
279
|
`Then add the top level \`main\` field to your configuration file:\n` +
|
|
@@ -238,7 +288,7 @@ function normalizeAndValidateBuild(
|
|
|
238
288
|
|
|
239
289
|
deprecated(
|
|
240
290
|
diagnostics,
|
|
241
|
-
|
|
291
|
+
rawEnv,
|
|
242
292
|
"build.upload.dir",
|
|
243
293
|
`Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`,
|
|
244
294
|
true
|
|
@@ -280,7 +330,7 @@ function normalizeAndValidateMainField(
|
|
|
280
330
|
const directory = path.resolve(configDir);
|
|
281
331
|
return path.resolve(directory, rawMain);
|
|
282
332
|
} else {
|
|
283
|
-
return;
|
|
333
|
+
return rawMain;
|
|
284
334
|
}
|
|
285
335
|
} else if (deprecatedUpload?.main !== undefined) {
|
|
286
336
|
const directory = path.resolve(
|
|
@@ -400,26 +450,91 @@ function normalizeAndValidateMigrations(
|
|
|
400
450
|
*/
|
|
401
451
|
function normalizeAndValidateSite(
|
|
402
452
|
diagnostics: Diagnostics,
|
|
403
|
-
|
|
453
|
+
configPath: string | undefined,
|
|
454
|
+
rawConfig: RawConfig,
|
|
455
|
+
mainEntryPoint: string | undefined
|
|
404
456
|
): Config["site"] {
|
|
405
|
-
if (
|
|
406
|
-
const { bucket, include = [], exclude = [], ...rest } =
|
|
407
|
-
|
|
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
|
+
]);
|
|
408
463
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
409
464
|
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
410
465
|
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
411
|
-
|
|
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
|
+
};
|
|
412
527
|
}
|
|
413
528
|
return undefined;
|
|
414
529
|
}
|
|
415
530
|
|
|
416
531
|
/**
|
|
417
|
-
* 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.
|
|
418
533
|
*/
|
|
419
534
|
function normalizeAndValidateModulePaths(
|
|
420
535
|
diagnostics: Diagnostics,
|
|
421
536
|
configPath: string | undefined,
|
|
422
|
-
field: "wasm_modules" | "text_blobs",
|
|
537
|
+
field: "wasm_modules" | "text_blobs" | "data_blobs",
|
|
423
538
|
rawMapping: Record<string, string> | undefined
|
|
424
539
|
): Record<string, string> | undefined {
|
|
425
540
|
if (rawMapping === undefined) {
|
|
@@ -442,14 +557,109 @@ function normalizeAndValidateModulePaths(
|
|
|
442
557
|
return mapping;
|
|
443
558
|
}
|
|
444
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
|
+
|
|
445
656
|
/**
|
|
446
657
|
* Validate top-level environment configuration and return the normalized values.
|
|
447
658
|
*/
|
|
448
659
|
function normalizeAndValidateEnvironment(
|
|
449
660
|
diagnostics: Diagnostics,
|
|
450
661
|
configPath: string | undefined,
|
|
451
|
-
topLevelEnv: RawEnvironment
|
|
452
|
-
deprecatedUpload: DeprecatedUpload | undefined
|
|
662
|
+
topLevelEnv: RawEnvironment
|
|
453
663
|
): Environment;
|
|
454
664
|
/**
|
|
455
665
|
* Validate the named environment configuration and return the normalized values.
|
|
@@ -458,7 +668,6 @@ function normalizeAndValidateEnvironment(
|
|
|
458
668
|
diagnostics: Diagnostics,
|
|
459
669
|
configPath: string | undefined,
|
|
460
670
|
rawEnv: RawEnvironment,
|
|
461
|
-
deprecatedUpload: DeprecatedUpload | undefined,
|
|
462
671
|
envName: string,
|
|
463
672
|
topLevelEnv: Environment,
|
|
464
673
|
isLegacyEnv: boolean,
|
|
@@ -468,7 +677,6 @@ function normalizeAndValidateEnvironment(
|
|
|
468
677
|
diagnostics: Diagnostics,
|
|
469
678
|
configPath: string | undefined,
|
|
470
679
|
rawEnv: RawEnvironment,
|
|
471
|
-
deprecatedUpload: DeprecatedUpload | undefined,
|
|
472
680
|
envName = "top level",
|
|
473
681
|
topLevelEnv?: Environment | undefined,
|
|
474
682
|
isLegacyEnv?: boolean,
|
|
@@ -510,39 +718,36 @@ function normalizeAndValidateEnvironment(
|
|
|
510
718
|
|
|
511
719
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
512
720
|
|
|
513
|
-
const route =
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
isString,
|
|
519
|
-
undefined
|
|
520
|
-
);
|
|
521
|
-
const routes = inheritable(
|
|
721
|
+
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
722
|
+
|
|
723
|
+
const routes = validateRoutes(diagnostics, topLevelEnv, rawEnv);
|
|
724
|
+
|
|
725
|
+
const workers_dev = inheritable(
|
|
522
726
|
diagnostics,
|
|
523
727
|
topLevelEnv,
|
|
524
728
|
rawEnv,
|
|
525
|
-
"
|
|
526
|
-
|
|
729
|
+
"workers_dev",
|
|
730
|
+
isBoolean,
|
|
527
731
|
undefined
|
|
528
732
|
);
|
|
529
|
-
|
|
733
|
+
|
|
734
|
+
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
530
735
|
diagnostics,
|
|
531
|
-
topLevelEnv,
|
|
532
736
|
rawEnv,
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
!(routes || route)
|
|
737
|
+
rawEnv.build ?? topLevelEnv?.build ?? {},
|
|
738
|
+
configPath
|
|
536
739
|
);
|
|
537
740
|
|
|
538
741
|
const environment: Environment = {
|
|
539
742
|
// Inherited fields
|
|
540
|
-
account_id:
|
|
743
|
+
account_id: inheritableInLegacyEnvironments(
|
|
541
744
|
diagnostics,
|
|
745
|
+
isLegacyEnv,
|
|
542
746
|
topLevelEnv,
|
|
543
747
|
rawEnv,
|
|
544
748
|
"account_id",
|
|
545
749
|
isString,
|
|
750
|
+
undefined,
|
|
546
751
|
undefined
|
|
547
752
|
),
|
|
548
753
|
compatibility_date: inheritable(
|
|
@@ -577,6 +782,12 @@ function normalizeAndValidateEnvironment(
|
|
|
577
782
|
isString,
|
|
578
783
|
"React.Fragment"
|
|
579
784
|
),
|
|
785
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
786
|
+
diagnostics,
|
|
787
|
+
topLevelEnv,
|
|
788
|
+
rawEnv,
|
|
789
|
+
configPath
|
|
790
|
+
),
|
|
580
791
|
rules: validateAndNormalizeRules(
|
|
581
792
|
diagnostics,
|
|
582
793
|
topLevelEnv,
|
|
@@ -590,7 +801,8 @@ function normalizeAndValidateEnvironment(
|
|
|
590
801
|
topLevelEnv,
|
|
591
802
|
rawEnv,
|
|
592
803
|
"name",
|
|
593
|
-
|
|
804
|
+
isValidName,
|
|
805
|
+
appendEnvName(envName),
|
|
594
806
|
undefined
|
|
595
807
|
),
|
|
596
808
|
main: normalizeAndValidateMainField(
|
|
@@ -623,6 +835,7 @@ function normalizeAndValidateEnvironment(
|
|
|
623
835
|
isOneOf("bundled", "unbound"),
|
|
624
836
|
undefined
|
|
625
837
|
),
|
|
838
|
+
build,
|
|
626
839
|
workers_dev,
|
|
627
840
|
// Not inherited fields
|
|
628
841
|
vars: notInheritable(
|
|
@@ -680,11 +893,36 @@ function normalizeAndValidateEnvironment(
|
|
|
680
893
|
}
|
|
681
894
|
),
|
|
682
895
|
zone_id: rawEnv.zone_id,
|
|
896
|
+
minify: rawEnv.minify,
|
|
897
|
+
node_compat: rawEnv.node_compat,
|
|
683
898
|
};
|
|
684
899
|
|
|
685
900
|
return environment;
|
|
686
901
|
}
|
|
687
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
|
+
|
|
688
926
|
const validateAndNormalizeRules = (
|
|
689
927
|
diagnostics: Diagnostics,
|
|
690
928
|
topLevelEnv: Environment | undefined,
|
|
@@ -700,7 +938,7 @@ const validateAndNormalizeRules = (
|
|
|
700
938
|
);
|
|
701
939
|
} else if (deprecatedRules) {
|
|
702
940
|
diagnostics.warnings.push(
|
|
703
|
-
`
|
|
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` +
|
|
704
942
|
"```\n" +
|
|
705
943
|
TOML.stringify({ rules: deprecatedRules }) +
|
|
706
944
|
"```"
|
|
@@ -873,7 +1111,7 @@ const validateBindingsProperty =
|
|
|
873
1111
|
diagnostics.warnings.push(
|
|
874
1112
|
`The following bindings are at the top level, but not on "env.${envName}".\n` +
|
|
875
1113
|
`This is not what you probably want, since "${field}" configuration is not inherited by environments.\n` +
|
|
876
|
-
`Please add a binding for each to "${fieldPath}.bindings"
|
|
1114
|
+
`Please add a binding for each to "${fieldPath}.bindings":\n` +
|
|
877
1115
|
missingBindings.map((name) => `- ${name}`).join("\n")
|
|
878
1116
|
);
|
|
879
1117
|
}
|
|
@@ -882,14 +1120,6 @@ const validateBindingsProperty =
|
|
|
882
1120
|
return isValid;
|
|
883
1121
|
};
|
|
884
1122
|
|
|
885
|
-
/**
|
|
886
|
-
* Get the names of the bindings collection in `value`.
|
|
887
|
-
*/
|
|
888
|
-
const getBindingNames = (value: unknown): string[] =>
|
|
889
|
-
((value as { bindings: { name: string }[] })?.bindings ?? []).map(
|
|
890
|
-
(binding) => binding.name
|
|
891
|
-
);
|
|
892
|
-
|
|
893
1123
|
/**
|
|
894
1124
|
* Check that the given field is a valid "durable_object" binding object.
|
|
895
1125
|
*/
|
|
@@ -1060,7 +1290,7 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1060
1290
|
const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
1061
1291
|
if (typeof value !== "object" || value === null) {
|
|
1062
1292
|
diagnostics.errors.push(
|
|
1063
|
-
`"
|
|
1293
|
+
`"r2_buckets" bindings should be objects, but got ${JSON.stringify(
|
|
1064
1294
|
value
|
|
1065
1295
|
)}`
|
|
1066
1296
|
);
|
|
@@ -1094,3 +1324,101 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1094
1324
|
}
|
|
1095
1325
|
return isValid;
|
|
1096
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
|
+
};
|