wrangler 0.0.0-e043479 → 0.0.0-e0a0509
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 +27 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +38 -25
- package/pages/functions/buildPlugin.ts +92 -0
- package/pages/functions/buildWorker.ts +80 -4
- package/pages/functions/filepath-routing.test.ts +136 -25
- package/pages/functions/filepath-routing.ts +14 -3
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +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 +1294 -355
- package/src/__tests__/dev.test.tsx +592 -12
- package/src/__tests__/guess-worker-format.test.ts +37 -18
- package/src/__tests__/helpers/mock-account-id.ts +4 -0
- package/src/__tests__/helpers/mock-cfetch.ts +8 -4
- 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-kv.ts +9 -16
- package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/run-in-tmp.ts +10 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +130 -0
- package/src/__tests__/index.test.ts +129 -753
- package/src/__tests__/init.test.ts +1516 -0
- package/src/__tests__/jest.setup.ts +13 -5
- package/src/__tests__/kv.test.ts +208 -174
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +327 -0
- package/src/__tests__/parse.test.ts +4 -0
- package/src/__tests__/publish.test.ts +3313 -505
- package/src/__tests__/r2.test.ts +38 -26
- package/src/__tests__/route.test.ts +45 -0
- 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 +26 -7
- package/src/bundle.ts +43 -7
- package/src/cfetch/internal.ts +9 -5
- package/src/cli.ts +5 -11
- package/src/config/README.md +7 -7
- package/src/config/config.ts +69 -105
- package/src/config/environment.ts +93 -4
- package/src/config/index.ts +15 -4
- package/src/config/validation-helpers.ts +228 -23
- package/src/config/validation.ts +559 -154
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +41 -13
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +33 -10
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +418 -0
- package/src/dev/local.tsx +312 -0
- package/src/dev/remote.tsx +213 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +222 -12
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +123 -0
- package/src/index.tsx +878 -482
- package/src/inspect.ts +25 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv.tsx → kv.ts} +7 -27
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/enum-keys.ts +17 -0
- package/src/miniflare-cli/index.ts +41 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +94 -6
- package/src/open-in-browser.ts +18 -5
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +892 -62
- package/src/parse.ts +4 -2
- package/src/proxy.ts +128 -55
- package/src/publish.ts +305 -199
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +88 -33
- 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 +244 -104
- package/src/whoami.tsx +2 -1
- package/src/{api/worker.ts → worker.ts} +15 -29
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +23568 -50489
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/__tests__/logout.test.ts +0 -50
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/dev.tsx +0 -960
- package/src/guess-worker-format.ts +0 -68
- package/src/reporting.ts +0 -115
- package/wrangler-dist/cli.js.map +0 -7
package/src/config/validation.ts
CHANGED
|
@@ -19,11 +19,24 @@ import {
|
|
|
19
19
|
validateOptionalTypedArray,
|
|
20
20
|
validateRequiredProperty,
|
|
21
21
|
validateTypedArray,
|
|
22
|
+
all,
|
|
23
|
+
isMutuallyExclusiveWith,
|
|
24
|
+
inheritableInLegacyEnvironments,
|
|
25
|
+
appendEnvName,
|
|
26
|
+
getBindingNames,
|
|
27
|
+
isValidName,
|
|
22
28
|
} from "./validation-helpers";
|
|
23
|
-
import type { Config,
|
|
24
|
-
import type {
|
|
29
|
+
import type { Config, DevConfig, RawConfig, RawDevConfig } from "./config";
|
|
30
|
+
import type {
|
|
31
|
+
RawEnvironment,
|
|
32
|
+
DeprecatedUpload,
|
|
33
|
+
Environment,
|
|
34
|
+
Rule,
|
|
35
|
+
} from "./environment";
|
|
25
36
|
import type { ValidatorFn } from "./validation-helpers";
|
|
26
37
|
|
|
38
|
+
const ENGLISH = new Intl.ListFormat("en");
|
|
39
|
+
|
|
27
40
|
/**
|
|
28
41
|
* Validate the given `rawConfig` object that was loaded from `configPath`.
|
|
29
42
|
*
|
|
@@ -34,7 +47,8 @@ import type { ValidatorFn } from "./validation-helpers";
|
|
|
34
47
|
*/
|
|
35
48
|
export function normalizeAndValidateConfig(
|
|
36
49
|
rawConfig: RawConfig,
|
|
37
|
-
configPath: string | undefined
|
|
50
|
+
configPath: string | undefined,
|
|
51
|
+
args: unknown
|
|
38
52
|
): {
|
|
39
53
|
config: Config;
|
|
40
54
|
diagnostics: Diagnostics;
|
|
@@ -48,23 +62,28 @@ export function normalizeAndValidateConfig(
|
|
|
48
62
|
deprecated(
|
|
49
63
|
diagnostics,
|
|
50
64
|
rawConfig,
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
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"
|
|
54
69
|
);
|
|
55
70
|
|
|
56
71
|
deprecated(
|
|
57
72
|
diagnostics,
|
|
58
73
|
rawConfig,
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
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"
|
|
62
78
|
);
|
|
63
79
|
|
|
64
|
-
|
|
80
|
+
deprecated(
|
|
65
81
|
diagnostics,
|
|
66
82
|
rawConfig,
|
|
67
|
-
|
|
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"
|
|
68
87
|
);
|
|
69
88
|
|
|
70
89
|
validateOptionalProperty(
|
|
@@ -75,29 +94,113 @@ export function normalizeAndValidateConfig(
|
|
|
75
94
|
"boolean"
|
|
76
95
|
);
|
|
77
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
|
+
|
|
113
|
+
// TODO: set the default to false to turn on service environments as the default
|
|
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
|
+
}
|
|
125
|
+
|
|
126
|
+
const topLevelEnv = normalizeAndValidateEnvironment(
|
|
127
|
+
diagnostics,
|
|
128
|
+
configPath,
|
|
129
|
+
rawConfig
|
|
130
|
+
);
|
|
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
|
+
|
|
135
|
+
let activeEnv = topLevelEnv;
|
|
136
|
+
if (envName !== undefined) {
|
|
137
|
+
const envDiagnostics = new Diagnostics(
|
|
138
|
+
`"env.${envName}" environment configuration`
|
|
139
|
+
);
|
|
140
|
+
const rawEnv = rawConfig.env?.[envName];
|
|
141
|
+
if (rawEnv !== undefined) {
|
|
142
|
+
activeEnv = normalizeAndValidateEnvironment(
|
|
143
|
+
envDiagnostics,
|
|
144
|
+
configPath,
|
|
145
|
+
rawEnv,
|
|
146
|
+
envName,
|
|
147
|
+
topLevelEnv,
|
|
148
|
+
isLegacyEnv,
|
|
149
|
+
rawConfig
|
|
150
|
+
);
|
|
151
|
+
diagnostics.addChild(envDiagnostics);
|
|
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
|
+
);
|
|
165
|
+
const envNames = rawConfig.env
|
|
166
|
+
? `The available configured environment names are: ${JSON.stringify(
|
|
167
|
+
Object.keys(rawConfig.env)
|
|
168
|
+
)}\n`
|
|
169
|
+
: "";
|
|
170
|
+
const message =
|
|
171
|
+
`No environment found in configuration with name "${envName}".\n` +
|
|
172
|
+
`Before using \`--env=${envName}\` there should be an equivalent environment section in the configuration.\n` +
|
|
173
|
+
`${envNames}\n` +
|
|
174
|
+
`Consider adding an environment configuration section to the wrangler.toml file:\n` +
|
|
175
|
+
"```\n[env." +
|
|
176
|
+
envName +
|
|
177
|
+
"]\n```\n";
|
|
178
|
+
|
|
179
|
+
if (envNames.length > 0) {
|
|
180
|
+
diagnostics.errors.push(message);
|
|
181
|
+
} else {
|
|
182
|
+
// Only warn (rather than error) if there are not actually any environments configured in wrangler.toml.
|
|
183
|
+
diagnostics.warnings.push(message);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
78
188
|
// Process the top-level default environment configuration.
|
|
79
189
|
const config: Config = {
|
|
80
190
|
configPath,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
configPath,
|
|
84
|
-
rawConfig.main,
|
|
85
|
-
deprecatedUpload
|
|
86
|
-
),
|
|
87
|
-
// TODO: set the default to false to turn on service environments as the default
|
|
88
|
-
legacy_env: rawConfig.legacy_env ?? true,
|
|
89
|
-
...normalizeAndValidateEnvironment(
|
|
90
|
-
diagnostics,
|
|
91
|
-
rawConfig,
|
|
92
|
-
deprecatedUpload.rules
|
|
93
|
-
),
|
|
94
|
-
env: {}, // Will be filled below by `normalizeAndValidateEnvironment()`.
|
|
191
|
+
legacy_env: isLegacyEnv,
|
|
192
|
+
...activeEnv,
|
|
95
193
|
dev: normalizeAndValidateDev(diagnostics, rawConfig.dev ?? {}),
|
|
96
194
|
migrations: normalizeAndValidateMigrations(
|
|
97
195
|
diagnostics,
|
|
98
196
|
rawConfig.migrations ?? []
|
|
99
197
|
),
|
|
100
|
-
site: normalizeAndValidateSite(
|
|
198
|
+
site: normalizeAndValidateSite(
|
|
199
|
+
diagnostics,
|
|
200
|
+
configPath,
|
|
201
|
+
rawConfig,
|
|
202
|
+
activeEnv.main
|
|
203
|
+
),
|
|
101
204
|
wasm_modules: normalizeAndValidateModulePaths(
|
|
102
205
|
diagnostics,
|
|
103
206
|
configPath,
|
|
@@ -110,33 +213,21 @@ export function normalizeAndValidateConfig(
|
|
|
110
213
|
"text_blobs",
|
|
111
214
|
rawConfig.text_blobs
|
|
112
215
|
),
|
|
113
|
-
|
|
216
|
+
data_blobs: normalizeAndValidateModulePaths(
|
|
217
|
+
diagnostics,
|
|
218
|
+
configPath,
|
|
219
|
+
"data_blobs",
|
|
220
|
+
rawConfig.data_blobs
|
|
221
|
+
),
|
|
114
222
|
};
|
|
115
223
|
|
|
116
|
-
|
|
117
|
-
if (rawConfig.env !== undefined) {
|
|
118
|
-
for (const envName of Object.keys(rawConfig.env)) {
|
|
119
|
-
const envDiagnostics = new Diagnostics(
|
|
120
|
-
`"env.${envName}" environment configuration`
|
|
121
|
-
);
|
|
122
|
-
const environment = normalizeAndValidateEnvironment(
|
|
123
|
-
envDiagnostics,
|
|
124
|
-
rawConfig.env[envName] as RawEnvironment,
|
|
125
|
-
deprecatedUpload.rules,
|
|
126
|
-
envName,
|
|
127
|
-
config,
|
|
128
|
-
rawConfig
|
|
129
|
-
);
|
|
130
|
-
config.env[envName] = environment;
|
|
131
|
-
diagnostics.addChild(envDiagnostics);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
224
|
+
validateBindingsHaveUniqueNames(diagnostics, config);
|
|
134
225
|
|
|
135
226
|
validateAdditionalProperties(
|
|
136
227
|
diagnostics,
|
|
137
228
|
"top-level",
|
|
138
229
|
Object.keys(rawConfig),
|
|
139
|
-
Object.keys(config)
|
|
230
|
+
[...Object.keys(config), "env"]
|
|
140
231
|
);
|
|
141
232
|
|
|
142
233
|
return { config, diagnostics };
|
|
@@ -147,8 +238,9 @@ export function normalizeAndValidateConfig(
|
|
|
147
238
|
*/
|
|
148
239
|
function normalizeAndValidateBuild(
|
|
149
240
|
diagnostics: Diagnostics,
|
|
150
|
-
|
|
151
|
-
rawBuild: Config["build"]
|
|
241
|
+
rawEnv: RawEnvironment,
|
|
242
|
+
rawBuild: Config["build"],
|
|
243
|
+
configPath: string | undefined
|
|
152
244
|
): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
|
|
153
245
|
const { command, cwd, watch_dir, upload, ...rest } = rawBuild;
|
|
154
246
|
const deprecatedUpload: DeprecatedUpload = { ...upload };
|
|
@@ -166,13 +258,13 @@ function normalizeAndValidateBuild(
|
|
|
166
258
|
|
|
167
259
|
deprecated(
|
|
168
260
|
diagnostics,
|
|
169
|
-
|
|
261
|
+
rawEnv,
|
|
170
262
|
"build.upload.format",
|
|
171
263
|
"The format is inferred automatically from the code.",
|
|
172
264
|
true
|
|
173
265
|
);
|
|
174
266
|
|
|
175
|
-
if (
|
|
267
|
+
if (rawEnv.main !== undefined && rawBuild.upload?.main) {
|
|
176
268
|
diagnostics.errors.push(
|
|
177
269
|
`Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.\n` +
|
|
178
270
|
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
@@ -181,7 +273,7 @@ function normalizeAndValidateBuild(
|
|
|
181
273
|
} else {
|
|
182
274
|
deprecated(
|
|
183
275
|
diagnostics,
|
|
184
|
-
|
|
276
|
+
rawEnv,
|
|
185
277
|
"build.upload.main",
|
|
186
278
|
`Delete the \`build.upload.main\` and \`build.upload.dir\` fields.\n` +
|
|
187
279
|
`Then add the top level \`main\` field to your configuration file:\n` +
|
|
@@ -196,24 +288,41 @@ function normalizeAndValidateBuild(
|
|
|
196
288
|
|
|
197
289
|
deprecated(
|
|
198
290
|
diagnostics,
|
|
199
|
-
|
|
291
|
+
rawEnv,
|
|
200
292
|
"build.upload.dir",
|
|
201
293
|
`Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`,
|
|
202
294
|
true
|
|
203
295
|
);
|
|
204
296
|
}
|
|
205
297
|
|
|
206
|
-
return {
|
|
298
|
+
return {
|
|
299
|
+
command,
|
|
300
|
+
watch_dir:
|
|
301
|
+
// - `watch_dir` only matters when `command` is defined, so we apply
|
|
302
|
+
// a default only when `command` is defined
|
|
303
|
+
// - `configPath` will always be defined since `build` can only
|
|
304
|
+
// be configured in `wrangler.toml`, but who knows, that may
|
|
305
|
+
// change in the future, so we do a check anyway
|
|
306
|
+
command
|
|
307
|
+
? configPath
|
|
308
|
+
? path.relative(
|
|
309
|
+
process.cwd(),
|
|
310
|
+
path.join(path.dirname(configPath), watch_dir || "./src")
|
|
311
|
+
)
|
|
312
|
+
: watch_dir || "./src"
|
|
313
|
+
: watch_dir,
|
|
314
|
+
cwd,
|
|
315
|
+
deprecatedUpload,
|
|
316
|
+
};
|
|
207
317
|
}
|
|
208
318
|
|
|
209
319
|
/**
|
|
210
320
|
* Validate the `main` field and return the normalized values.
|
|
211
321
|
*/
|
|
212
322
|
function normalizeAndValidateMainField(
|
|
213
|
-
diagnostics: Diagnostics,
|
|
214
323
|
configPath: string | undefined,
|
|
215
324
|
rawMain: string | undefined,
|
|
216
|
-
deprecatedUpload:
|
|
325
|
+
deprecatedUpload: DeprecatedUpload | undefined
|
|
217
326
|
): string | undefined {
|
|
218
327
|
const configDir = path.dirname(configPath ?? "wrangler.toml");
|
|
219
328
|
if (rawMain !== undefined) {
|
|
@@ -221,13 +330,13 @@ function normalizeAndValidateMainField(
|
|
|
221
330
|
const directory = path.resolve(configDir);
|
|
222
331
|
return path.resolve(directory, rawMain);
|
|
223
332
|
} else {
|
|
224
|
-
|
|
225
|
-
`ERROR: "main" should be a string but got ${JSON.stringify(rawMain)}`
|
|
226
|
-
);
|
|
227
|
-
return;
|
|
333
|
+
return rawMain;
|
|
228
334
|
}
|
|
229
|
-
} else if (deprecatedUpload
|
|
230
|
-
const directory = path.resolve(
|
|
335
|
+
} else if (deprecatedUpload?.main !== undefined) {
|
|
336
|
+
const directory = path.resolve(
|
|
337
|
+
configDir,
|
|
338
|
+
deprecatedUpload?.dir || "./dist"
|
|
339
|
+
);
|
|
231
340
|
return path.resolve(directory, deprecatedUpload.main);
|
|
232
341
|
} else {
|
|
233
342
|
return;
|
|
@@ -239,11 +348,11 @@ function normalizeAndValidateMainField(
|
|
|
239
348
|
*/
|
|
240
349
|
function normalizeAndValidateDev(
|
|
241
350
|
diagnostics: Diagnostics,
|
|
242
|
-
rawDev:
|
|
243
|
-
):
|
|
351
|
+
rawDev: RawDevConfig
|
|
352
|
+
): DevConfig {
|
|
244
353
|
const {
|
|
245
|
-
ip = "
|
|
246
|
-
port
|
|
354
|
+
ip = "localhost",
|
|
355
|
+
port,
|
|
247
356
|
local_protocol = "http",
|
|
248
357
|
upstream_protocol = "https",
|
|
249
358
|
host,
|
|
@@ -258,14 +367,16 @@ function normalizeAndValidateDev(
|
|
|
258
367
|
"dev",
|
|
259
368
|
"local_protocol",
|
|
260
369
|
local_protocol,
|
|
261
|
-
"string"
|
|
370
|
+
"string",
|
|
371
|
+
["http", "https"]
|
|
262
372
|
);
|
|
263
373
|
validateOptionalProperty(
|
|
264
374
|
diagnostics,
|
|
265
375
|
"dev",
|
|
266
376
|
"upstream_protocol",
|
|
267
377
|
upstream_protocol,
|
|
268
|
-
"string"
|
|
378
|
+
"string",
|
|
379
|
+
["http", "https"]
|
|
269
380
|
);
|
|
270
381
|
validateOptionalProperty(diagnostics, "dev", "host", host, "string");
|
|
271
382
|
return { ip, port, local_protocol, upstream_protocol, host };
|
|
@@ -304,7 +415,7 @@ function normalizeAndValidateMigrations(
|
|
|
304
415
|
if (migration.renamed_classes !== undefined) {
|
|
305
416
|
if (!Array.isArray(migration.renamed_classes)) {
|
|
306
417
|
diagnostics.errors.push(
|
|
307
|
-
`"migrations[${i}].renamed_classes"
|
|
418
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
308
419
|
migration.renamed_classes
|
|
309
420
|
)}.`
|
|
310
421
|
);
|
|
@@ -317,7 +428,7 @@ function normalizeAndValidateMigrations(
|
|
|
317
428
|
)
|
|
318
429
|
) {
|
|
319
430
|
diagnostics.errors.push(
|
|
320
|
-
`"migrations[${i}].renamed_classes"
|
|
431
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
321
432
|
migration.renamed_classes
|
|
322
433
|
)}.`
|
|
323
434
|
);
|
|
@@ -339,39 +450,91 @@ function normalizeAndValidateMigrations(
|
|
|
339
450
|
*/
|
|
340
451
|
function normalizeAndValidateSite(
|
|
341
452
|
diagnostics: Diagnostics,
|
|
342
|
-
|
|
453
|
+
configPath: string | undefined,
|
|
454
|
+
rawConfig: RawConfig,
|
|
455
|
+
mainEntryPoint: string | undefined
|
|
343
456
|
): Config["site"] {
|
|
344
|
-
if (
|
|
345
|
-
const {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
...rest
|
|
351
|
-
} = rawSite;
|
|
352
|
-
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), []);
|
|
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
|
+
]);
|
|
353
463
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
464
|
+
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
465
|
+
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
354
466
|
validateOptionalProperty(
|
|
355
467
|
diagnostics,
|
|
356
468
|
"site",
|
|
357
|
-
"
|
|
358
|
-
|
|
469
|
+
"entry-point",
|
|
470
|
+
rawConfig.site["entry-point"],
|
|
359
471
|
"string"
|
|
360
472
|
);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
+
};
|
|
364
527
|
}
|
|
365
528
|
return undefined;
|
|
366
529
|
}
|
|
367
530
|
|
|
368
531
|
/**
|
|
369
|
-
* 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.
|
|
370
533
|
*/
|
|
371
534
|
function normalizeAndValidateModulePaths(
|
|
372
535
|
diagnostics: Diagnostics,
|
|
373
536
|
configPath: string | undefined,
|
|
374
|
-
field: "wasm_modules" | "text_blobs",
|
|
537
|
+
field: "wasm_modules" | "text_blobs" | "data_blobs",
|
|
375
538
|
rawMapping: Record<string, string> | undefined
|
|
376
539
|
): Record<string, string> | undefined {
|
|
377
540
|
if (rawMapping === undefined) {
|
|
@@ -394,31 +557,129 @@ function normalizeAndValidateModulePaths(
|
|
|
394
557
|
return mapping;
|
|
395
558
|
}
|
|
396
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
|
+
|
|
397
656
|
/**
|
|
398
657
|
* Validate top-level environment configuration and return the normalized values.
|
|
399
658
|
*/
|
|
400
659
|
function normalizeAndValidateEnvironment(
|
|
401
660
|
diagnostics: Diagnostics,
|
|
402
|
-
|
|
403
|
-
|
|
661
|
+
configPath: string | undefined,
|
|
662
|
+
topLevelEnv: RawEnvironment
|
|
404
663
|
): Environment;
|
|
405
664
|
/**
|
|
406
665
|
* Validate the named environment configuration and return the normalized values.
|
|
407
666
|
*/
|
|
408
667
|
function normalizeAndValidateEnvironment(
|
|
409
668
|
diagnostics: Diagnostics,
|
|
669
|
+
configPath: string | undefined,
|
|
410
670
|
rawEnv: RawEnvironment,
|
|
411
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
412
671
|
envName: string,
|
|
413
|
-
|
|
672
|
+
topLevelEnv: Environment,
|
|
673
|
+
isLegacyEnv: boolean,
|
|
414
674
|
rawConfig: RawConfig
|
|
415
675
|
): Environment;
|
|
416
676
|
function normalizeAndValidateEnvironment(
|
|
417
677
|
diagnostics: Diagnostics,
|
|
678
|
+
configPath: string | undefined,
|
|
418
679
|
rawEnv: RawEnvironment,
|
|
419
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
420
680
|
envName = "top level",
|
|
421
|
-
|
|
681
|
+
topLevelEnv?: Environment | undefined,
|
|
682
|
+
isLegacyEnv?: boolean,
|
|
422
683
|
rawConfig?: RawConfig | undefined
|
|
423
684
|
): Environment {
|
|
424
685
|
deprecated(
|
|
@@ -457,44 +718,41 @@ function normalizeAndValidateEnvironment(
|
|
|
457
718
|
|
|
458
719
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
459
720
|
|
|
460
|
-
const route =
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
isString,
|
|
466
|
-
undefined
|
|
467
|
-
);
|
|
468
|
-
const routes = inheritable(
|
|
721
|
+
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
722
|
+
|
|
723
|
+
const routes = validateRoutes(diagnostics, topLevelEnv, rawEnv);
|
|
724
|
+
|
|
725
|
+
const workers_dev = inheritable(
|
|
469
726
|
diagnostics,
|
|
470
|
-
|
|
727
|
+
topLevelEnv,
|
|
471
728
|
rawEnv,
|
|
472
|
-
"
|
|
473
|
-
|
|
729
|
+
"workers_dev",
|
|
730
|
+
isBoolean,
|
|
474
731
|
undefined
|
|
475
732
|
);
|
|
476
|
-
|
|
733
|
+
|
|
734
|
+
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
477
735
|
diagnostics,
|
|
478
|
-
config,
|
|
479
736
|
rawEnv,
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
!(routes || route)
|
|
737
|
+
rawEnv.build ?? topLevelEnv?.build ?? {},
|
|
738
|
+
configPath
|
|
483
739
|
);
|
|
484
740
|
|
|
485
741
|
const environment: Environment = {
|
|
486
742
|
// Inherited fields
|
|
487
|
-
account_id:
|
|
743
|
+
account_id: inheritableInLegacyEnvironments(
|
|
488
744
|
diagnostics,
|
|
489
|
-
|
|
745
|
+
isLegacyEnv,
|
|
746
|
+
topLevelEnv,
|
|
490
747
|
rawEnv,
|
|
491
748
|
"account_id",
|
|
492
749
|
isString,
|
|
750
|
+
undefined,
|
|
493
751
|
undefined
|
|
494
752
|
),
|
|
495
753
|
compatibility_date: inheritable(
|
|
496
754
|
diagnostics,
|
|
497
|
-
|
|
755
|
+
topLevelEnv,
|
|
498
756
|
rawEnv,
|
|
499
757
|
"compatibility_date",
|
|
500
758
|
isString,
|
|
@@ -502,7 +760,7 @@ function normalizeAndValidateEnvironment(
|
|
|
502
760
|
),
|
|
503
761
|
compatibility_flags: inheritable(
|
|
504
762
|
diagnostics,
|
|
505
|
-
|
|
763
|
+
topLevelEnv,
|
|
506
764
|
rawEnv,
|
|
507
765
|
"compatibility_flags",
|
|
508
766
|
isStringArray,
|
|
@@ -510,7 +768,7 @@ function normalizeAndValidateEnvironment(
|
|
|
510
768
|
),
|
|
511
769
|
jsx_factory: inheritable(
|
|
512
770
|
diagnostics,
|
|
513
|
-
|
|
771
|
+
topLevelEnv,
|
|
514
772
|
rawEnv,
|
|
515
773
|
"jsx_factory",
|
|
516
774
|
isString,
|
|
@@ -518,25 +776,52 @@ function normalizeAndValidateEnvironment(
|
|
|
518
776
|
),
|
|
519
777
|
jsx_fragment: inheritable(
|
|
520
778
|
diagnostics,
|
|
521
|
-
|
|
779
|
+
topLevelEnv,
|
|
522
780
|
rawEnv,
|
|
523
781
|
"jsx_fragment",
|
|
524
782
|
isString,
|
|
525
783
|
"React.Fragment"
|
|
526
784
|
),
|
|
785
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
786
|
+
diagnostics,
|
|
787
|
+
topLevelEnv,
|
|
788
|
+
rawEnv,
|
|
789
|
+
configPath
|
|
790
|
+
),
|
|
527
791
|
rules: validateAndNormalizeRules(
|
|
528
792
|
diagnostics,
|
|
529
|
-
|
|
793
|
+
topLevelEnv,
|
|
530
794
|
rawEnv,
|
|
531
|
-
|
|
795
|
+
deprecatedUpload?.rules,
|
|
532
796
|
envName
|
|
533
797
|
),
|
|
534
|
-
name:
|
|
798
|
+
name: inheritableInLegacyEnvironments(
|
|
799
|
+
diagnostics,
|
|
800
|
+
isLegacyEnv,
|
|
801
|
+
topLevelEnv,
|
|
802
|
+
rawEnv,
|
|
803
|
+
"name",
|
|
804
|
+
isValidName,
|
|
805
|
+
appendEnvName(envName),
|
|
806
|
+
undefined
|
|
807
|
+
),
|
|
808
|
+
main: normalizeAndValidateMainField(
|
|
809
|
+
configPath,
|
|
810
|
+
inheritable(
|
|
811
|
+
diagnostics,
|
|
812
|
+
topLevelEnv,
|
|
813
|
+
rawEnv,
|
|
814
|
+
"main",
|
|
815
|
+
isString,
|
|
816
|
+
undefined
|
|
817
|
+
),
|
|
818
|
+
deprecatedUpload
|
|
819
|
+
),
|
|
535
820
|
route,
|
|
536
821
|
routes,
|
|
537
822
|
triggers: inheritable(
|
|
538
823
|
diagnostics,
|
|
539
|
-
|
|
824
|
+
topLevelEnv,
|
|
540
825
|
rawEnv,
|
|
541
826
|
"triggers",
|
|
542
827
|
isObjectWith("crons"),
|
|
@@ -544,17 +829,18 @@ function normalizeAndValidateEnvironment(
|
|
|
544
829
|
),
|
|
545
830
|
usage_model: inheritable(
|
|
546
831
|
diagnostics,
|
|
547
|
-
|
|
832
|
+
topLevelEnv,
|
|
548
833
|
rawEnv,
|
|
549
834
|
"usage_model",
|
|
550
835
|
isOneOf("bundled", "unbound"),
|
|
551
836
|
undefined
|
|
552
837
|
),
|
|
838
|
+
build,
|
|
553
839
|
workers_dev,
|
|
554
840
|
// Not inherited fields
|
|
555
841
|
vars: notInheritable(
|
|
556
842
|
diagnostics,
|
|
557
|
-
|
|
843
|
+
topLevelEnv,
|
|
558
844
|
rawConfig,
|
|
559
845
|
rawEnv,
|
|
560
846
|
envName,
|
|
@@ -564,7 +850,7 @@ function normalizeAndValidateEnvironment(
|
|
|
564
850
|
),
|
|
565
851
|
durable_objects: notInheritable(
|
|
566
852
|
diagnostics,
|
|
567
|
-
|
|
853
|
+
topLevelEnv,
|
|
568
854
|
rawConfig,
|
|
569
855
|
rawEnv,
|
|
570
856
|
envName,
|
|
@@ -576,7 +862,7 @@ function normalizeAndValidateEnvironment(
|
|
|
576
862
|
),
|
|
577
863
|
kv_namespaces: notInheritable(
|
|
578
864
|
diagnostics,
|
|
579
|
-
|
|
865
|
+
topLevelEnv,
|
|
580
866
|
rawConfig,
|
|
581
867
|
rawEnv,
|
|
582
868
|
envName,
|
|
@@ -586,7 +872,7 @@ function normalizeAndValidateEnvironment(
|
|
|
586
872
|
),
|
|
587
873
|
r2_buckets: notInheritable(
|
|
588
874
|
diagnostics,
|
|
589
|
-
|
|
875
|
+
topLevelEnv,
|
|
590
876
|
rawConfig,
|
|
591
877
|
rawEnv,
|
|
592
878
|
envName,
|
|
@@ -596,7 +882,7 @@ function normalizeAndValidateEnvironment(
|
|
|
596
882
|
),
|
|
597
883
|
unsafe: notInheritable(
|
|
598
884
|
diagnostics,
|
|
599
|
-
|
|
885
|
+
topLevelEnv,
|
|
600
886
|
rawConfig,
|
|
601
887
|
rawEnv,
|
|
602
888
|
envName,
|
|
@@ -607,27 +893,52 @@ function normalizeAndValidateEnvironment(
|
|
|
607
893
|
}
|
|
608
894
|
),
|
|
609
895
|
zone_id: rawEnv.zone_id,
|
|
896
|
+
minify: rawEnv.minify,
|
|
897
|
+
node_compat: rawEnv.node_compat,
|
|
610
898
|
};
|
|
611
899
|
|
|
612
900
|
return environment;
|
|
613
901
|
}
|
|
614
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
|
+
|
|
615
926
|
const validateAndNormalizeRules = (
|
|
616
927
|
diagnostics: Diagnostics,
|
|
617
|
-
|
|
928
|
+
topLevelEnv: Environment | undefined,
|
|
618
929
|
rawEnv: RawEnvironment,
|
|
619
930
|
deprecatedRules: Rule[] | undefined,
|
|
620
931
|
envName: string
|
|
621
932
|
): Rule[] => {
|
|
622
|
-
if (
|
|
933
|
+
if (topLevelEnv === undefined) {
|
|
623
934
|
// Only create errors/warnings for the top-level environment
|
|
624
935
|
if (rawEnv.rules && deprecatedRules) {
|
|
625
936
|
diagnostics.errors.push(
|
|
626
|
-
`
|
|
937
|
+
`You cannot configure both [rules] and [build.upload.rules] in your wrangler.toml. Delete the \`build.upload\` section.`
|
|
627
938
|
);
|
|
628
939
|
} else if (deprecatedRules) {
|
|
629
940
|
diagnostics.warnings.push(
|
|
630
|
-
`
|
|
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` +
|
|
631
942
|
"```\n" +
|
|
632
943
|
TOML.stringify({ rules: deprecatedRules }) +
|
|
633
944
|
"```"
|
|
@@ -637,7 +948,7 @@ const validateAndNormalizeRules = (
|
|
|
637
948
|
|
|
638
949
|
return inheritable(
|
|
639
950
|
diagnostics,
|
|
640
|
-
|
|
951
|
+
topLevelEnv,
|
|
641
952
|
rawEnv,
|
|
642
953
|
"rules",
|
|
643
954
|
validateRules(envName),
|
|
@@ -673,7 +984,9 @@ const validateRules =
|
|
|
673
984
|
|
|
674
985
|
const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
675
986
|
if (typeof value !== "object" || value === null) {
|
|
676
|
-
diagnostics.errors.push(
|
|
987
|
+
diagnostics.errors.push(
|
|
988
|
+
`"${field}" should be an object but got ${JSON.stringify(value)}.`
|
|
989
|
+
);
|
|
677
990
|
return false;
|
|
678
991
|
}
|
|
679
992
|
// Rules must have a type string and glob string array, and optionally a fallthrough boolean.
|
|
@@ -690,7 +1003,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
690
1003
|
])
|
|
691
1004
|
) {
|
|
692
1005
|
diagnostics.errors.push(
|
|
693
|
-
`
|
|
1006
|
+
`bindings should have a string "type" field, which contains one of "ESModule", "CommonJS", "CompiledWasm", "Text", or "Data".`
|
|
694
1007
|
);
|
|
695
1008
|
isValid = false;
|
|
696
1009
|
}
|
|
@@ -701,7 +1014,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
701
1014
|
|
|
702
1015
|
if (!isOptionalProperty(rule, "fallthrough", "boolean")) {
|
|
703
1016
|
diagnostics.errors.push(
|
|
704
|
-
`
|
|
1017
|
+
`binding should, optionally, have a boolean "fallthrough" field.`
|
|
705
1018
|
);
|
|
706
1019
|
isValid = false;
|
|
707
1020
|
}
|
|
@@ -798,7 +1111,7 @@ const validateBindingsProperty =
|
|
|
798
1111
|
diagnostics.warnings.push(
|
|
799
1112
|
`The following bindings are at the top level, but not on "env.${envName}".\n` +
|
|
800
1113
|
`This is not what you probably want, since "${field}" configuration is not inherited by environments.\n` +
|
|
801
|
-
`Please add a binding for each to "${fieldPath}.bindings"
|
|
1114
|
+
`Please add a binding for each to "${fieldPath}.bindings":\n` +
|
|
802
1115
|
missingBindings.map((name) => `- ${name}`).join("\n")
|
|
803
1116
|
);
|
|
804
1117
|
}
|
|
@@ -807,42 +1120,34 @@ const validateBindingsProperty =
|
|
|
807
1120
|
return isValid;
|
|
808
1121
|
};
|
|
809
1122
|
|
|
810
|
-
/**
|
|
811
|
-
* Get the names of the bindings collection in `value`.
|
|
812
|
-
*/
|
|
813
|
-
const getBindingNames = (value: unknown): string[] =>
|
|
814
|
-
((value as { bindings: { name: string }[] })?.bindings ?? []).map(
|
|
815
|
-
(binding) => binding.name
|
|
816
|
-
);
|
|
817
|
-
|
|
818
1123
|
/**
|
|
819
1124
|
* Check that the given field is a valid "durable_object" binding object.
|
|
820
1125
|
*/
|
|
821
1126
|
const validateDurableObjectBinding: ValidatorFn = (
|
|
822
1127
|
diagnostics,
|
|
823
|
-
|
|
1128
|
+
field,
|
|
824
1129
|
value
|
|
825
1130
|
) => {
|
|
826
1131
|
if (typeof value !== "object" || value === null) {
|
|
827
|
-
diagnostics.errors.push(
|
|
1132
|
+
diagnostics.errors.push(
|
|
1133
|
+
`Expected "${field}" to be an object but got ${JSON.stringify(value)}`
|
|
1134
|
+
);
|
|
828
1135
|
return false;
|
|
829
1136
|
}
|
|
830
1137
|
|
|
831
1138
|
// Durable Object bindings must have a name and class_name, and optionally a script_name.
|
|
832
1139
|
let isValid = true;
|
|
833
1140
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
834
|
-
diagnostics.errors.push(
|
|
835
|
-
`ERROR: bindings should have a string "name" field.`
|
|
836
|
-
);
|
|
1141
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
837
1142
|
isValid = false;
|
|
838
1143
|
}
|
|
839
1144
|
if (!isRequiredProperty(value, "class_name", "string")) {
|
|
840
|
-
diagnostics.errors.push(`
|
|
1145
|
+
diagnostics.errors.push(`binding should have a string "class_name" field.`);
|
|
841
1146
|
isValid = false;
|
|
842
1147
|
}
|
|
843
1148
|
if (!isOptionalProperty(value, "script_name", "string")) {
|
|
844
1149
|
diagnostics.errors.push(
|
|
845
|
-
`
|
|
1150
|
+
`binding should, optionally, have a string "script_name" field.`
|
|
846
1151
|
);
|
|
847
1152
|
isValid = false;
|
|
848
1153
|
}
|
|
@@ -855,16 +1160,18 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
855
1160
|
*
|
|
856
1161
|
* TODO: further validation of known unsafe bindings.
|
|
857
1162
|
*/
|
|
858
|
-
const validateUnsafeBinding: ValidatorFn = (diagnostics,
|
|
1163
|
+
const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
859
1164
|
if (typeof value !== "object" || value === null) {
|
|
860
|
-
diagnostics.errors.push(
|
|
1165
|
+
diagnostics.errors.push(
|
|
1166
|
+
`Expected ${field} to be an object but got ${JSON.stringify(value)}.`
|
|
1167
|
+
);
|
|
861
1168
|
return false;
|
|
862
1169
|
}
|
|
863
1170
|
|
|
864
1171
|
let isValid = true;
|
|
865
1172
|
// Unsafe bindings must have a name and type.
|
|
866
1173
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
867
|
-
diagnostics.errors.push(`
|
|
1174
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
868
1175
|
isValid = false;
|
|
869
1176
|
}
|
|
870
1177
|
if (isRequiredProperty(value, "type", "string")) {
|
|
@@ -883,7 +1190,7 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, _field, value) => {
|
|
|
883
1190
|
);
|
|
884
1191
|
}
|
|
885
1192
|
} else {
|
|
886
|
-
diagnostics.errors.push(`
|
|
1193
|
+
diagnostics.errors.push(`binding should have a string "type" field.`);
|
|
887
1194
|
isValid = false;
|
|
888
1195
|
}
|
|
889
1196
|
return isValid;
|
|
@@ -983,7 +1290,7 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
983
1290
|
const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
984
1291
|
if (typeof value !== "object" || value === null) {
|
|
985
1292
|
diagnostics.errors.push(
|
|
986
|
-
`"
|
|
1293
|
+
`"r2_buckets" bindings should be objects, but got ${JSON.stringify(
|
|
987
1294
|
value
|
|
988
1295
|
)}`
|
|
989
1296
|
);
|
|
@@ -1017,3 +1324,101 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1017
1324
|
}
|
|
1018
1325
|
return isValid;
|
|
1019
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
|
+
};
|