wrangler 0.0.0-e3cab74 → 0.0.0-e452a35
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/Cloudflare_CA.pem +18 -0
- package/README.md +27 -14
- package/bin/wrangler.js +49 -5
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +42 -28
- package/pages/functions/buildPlugin.ts +105 -0
- package/pages/functions/buildWorker.ts +93 -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 +147 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +1514 -367
- package/src/__tests__/dev.test.tsx +870 -84
- package/src/__tests__/guess-worker-format.test.ts +37 -18
- package/src/__tests__/helpers/mock-account-id.ts +22 -4
- package/src/__tests__/helpers/mock-cfetch.ts +8 -4
- package/src/__tests__/helpers/mock-console.ts +35 -10
- 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/mock-stdin.ts +103 -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 +137 -747
- package/src/__tests__/init.test.ts +1557 -0
- package/src/__tests__/jest.setup.ts +28 -8
- package/src/__tests__/kv.test.ts +598 -258
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +657 -0
- package/src/__tests__/parse.test.ts +8 -0
- package/src/__tests__/publish.test.ts +4003 -941
- package/src/__tests__/r2.test.ts +69 -34
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +228 -73
- 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/abort.d.ts +3 -0
- package/src/bundle.ts +74 -7
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +20 -14
- package/src/cli.ts +5 -11
- package/src/config/README.md +7 -7
- package/src/config/config.ts +69 -100
- package/src/config/environment.ts +119 -4
- package/src/config/index.ts +177 -4
- package/src/config/validation-helpers.ts +228 -23
- package/src/config/validation.ts +687 -174
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +74 -36
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +55 -18
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +422 -0
- package/src/dev/local.tsx +318 -0
- package/src/dev/remote.tsx +227 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +16 -6
- package/src/durable.ts +102 -0
- package/src/entry.ts +279 -14
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +123 -0
- package/src/index.tsx +1268 -806
- package/src/inspect.ts +64 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv.tsx → kv.ts} +195 -62
- 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 +9 -3
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +1057 -75
- package/src/parse.ts +24 -5
- package/src/proxy.ts +143 -54
- package/src/publish.ts +444 -229
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +98 -44
- 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 +263 -109
- package/src/whoami.tsx +2 -1
- package/src/{api/worker.ts → worker.ts} +24 -30
- package/templates/gitignore +171 -0
- package/templates/new-worker.ts +16 -1
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +55345 -69246
- 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 -961
- 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,98 @@ export function normalizeAndValidateConfig(
|
|
|
75
94
|
"boolean"
|
|
76
95
|
);
|
|
77
96
|
|
|
97
|
+
// TODO: set the default to false to turn on service environments as the default
|
|
98
|
+
const isLegacyEnv =
|
|
99
|
+
(args as { "legacy-env": boolean | undefined })["legacy-env"] ??
|
|
100
|
+
rawConfig.legacy_env ??
|
|
101
|
+
true;
|
|
102
|
+
|
|
103
|
+
// TODO: remove this once service environments goes GA.
|
|
104
|
+
if (!isLegacyEnv) {
|
|
105
|
+
diagnostics.warnings.push(
|
|
106
|
+
"Experimental: Service environments are in beta, and their behaviour is guaranteed to change in the future. DO NOT USE IN PRODUCTION."
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const topLevelEnv = normalizeAndValidateEnvironment(
|
|
111
|
+
diagnostics,
|
|
112
|
+
configPath,
|
|
113
|
+
rawConfig
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
//TODO: find a better way to define the type of Args that can be passed to the normalizeAndValidateConfig()
|
|
117
|
+
const envName = (args as { env: string | undefined }).env;
|
|
118
|
+
|
|
119
|
+
let activeEnv = topLevelEnv;
|
|
120
|
+
if (envName !== undefined) {
|
|
121
|
+
const envDiagnostics = new Diagnostics(
|
|
122
|
+
`"env.${envName}" environment configuration`
|
|
123
|
+
);
|
|
124
|
+
const rawEnv = rawConfig.env?.[envName];
|
|
125
|
+
if (rawEnv !== undefined) {
|
|
126
|
+
activeEnv = normalizeAndValidateEnvironment(
|
|
127
|
+
envDiagnostics,
|
|
128
|
+
configPath,
|
|
129
|
+
rawEnv,
|
|
130
|
+
envName,
|
|
131
|
+
topLevelEnv,
|
|
132
|
+
isLegacyEnv,
|
|
133
|
+
rawConfig
|
|
134
|
+
);
|
|
135
|
+
diagnostics.addChild(envDiagnostics);
|
|
136
|
+
} else {
|
|
137
|
+
// An environment was specified, but no configuration for it was found.
|
|
138
|
+
// To cover any legacy environment cases, where the `envName` is used,
|
|
139
|
+
// Let's create a fake active environment with the specified `envName`.
|
|
140
|
+
activeEnv = normalizeAndValidateEnvironment(
|
|
141
|
+
envDiagnostics,
|
|
142
|
+
configPath,
|
|
143
|
+
{},
|
|
144
|
+
envName,
|
|
145
|
+
topLevelEnv,
|
|
146
|
+
isLegacyEnv,
|
|
147
|
+
rawConfig
|
|
148
|
+
);
|
|
149
|
+
const envNames = rawConfig.env
|
|
150
|
+
? `The available configured environment names are: ${JSON.stringify(
|
|
151
|
+
Object.keys(rawConfig.env)
|
|
152
|
+
)}\n`
|
|
153
|
+
: "";
|
|
154
|
+
const message =
|
|
155
|
+
`No environment found in configuration with name "${envName}".\n` +
|
|
156
|
+
`Before using \`--env=${envName}\` there should be an equivalent environment section in the configuration.\n` +
|
|
157
|
+
`${envNames}\n` +
|
|
158
|
+
`Consider adding an environment configuration section to the wrangler.toml file:\n` +
|
|
159
|
+
"```\n[env." +
|
|
160
|
+
envName +
|
|
161
|
+
"]\n```\n";
|
|
162
|
+
|
|
163
|
+
if (envNames.length > 0) {
|
|
164
|
+
diagnostics.errors.push(message);
|
|
165
|
+
} else {
|
|
166
|
+
// Only warn (rather than error) if there are not actually any environments configured in wrangler.toml.
|
|
167
|
+
diagnostics.warnings.push(message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
78
172
|
// Process the top-level default environment configuration.
|
|
79
173
|
const config: Config = {
|
|
80
174
|
configPath,
|
|
81
|
-
|
|
175
|
+
legacy_env: isLegacyEnv,
|
|
176
|
+
...activeEnv,
|
|
177
|
+
dev: normalizeAndValidateDev(diagnostics, rawConfig.dev ?? {}),
|
|
178
|
+
migrations: normalizeAndValidateMigrations(
|
|
82
179
|
diagnostics,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
deprecatedUpload
|
|
180
|
+
rawConfig.migrations ?? [],
|
|
181
|
+
activeEnv.durable_objects
|
|
86
182
|
),
|
|
87
|
-
|
|
88
|
-
legacy_env: rawConfig.legacy_env ?? true,
|
|
89
|
-
...normalizeAndValidateEnvironment(
|
|
183
|
+
site: normalizeAndValidateSite(
|
|
90
184
|
diagnostics,
|
|
185
|
+
configPath,
|
|
91
186
|
rawConfig,
|
|
92
|
-
|
|
93
|
-
),
|
|
94
|
-
env: {}, // Will be filled below by `normalizeAndValidateEnvironment()`.
|
|
95
|
-
dev: normalizeAndValidateDev(diagnostics, rawConfig.dev ?? {}),
|
|
96
|
-
migrations: normalizeAndValidateMigrations(
|
|
97
|
-
diagnostics,
|
|
98
|
-
rawConfig.migrations ?? []
|
|
187
|
+
activeEnv.main
|
|
99
188
|
),
|
|
100
|
-
site: normalizeAndValidateSite(diagnostics, rawConfig.site),
|
|
101
189
|
wasm_modules: normalizeAndValidateModulePaths(
|
|
102
190
|
diagnostics,
|
|
103
191
|
configPath,
|
|
@@ -110,33 +198,21 @@ export function normalizeAndValidateConfig(
|
|
|
110
198
|
"text_blobs",
|
|
111
199
|
rawConfig.text_blobs
|
|
112
200
|
),
|
|
113
|
-
|
|
201
|
+
data_blobs: normalizeAndValidateModulePaths(
|
|
202
|
+
diagnostics,
|
|
203
|
+
configPath,
|
|
204
|
+
"data_blobs",
|
|
205
|
+
rawConfig.data_blobs
|
|
206
|
+
),
|
|
114
207
|
};
|
|
115
208
|
|
|
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
|
-
}
|
|
209
|
+
validateBindingsHaveUniqueNames(diagnostics, config);
|
|
134
210
|
|
|
135
211
|
validateAdditionalProperties(
|
|
136
212
|
diagnostics,
|
|
137
213
|
"top-level",
|
|
138
214
|
Object.keys(rawConfig),
|
|
139
|
-
Object.keys(config)
|
|
215
|
+
[...Object.keys(config), "env"]
|
|
140
216
|
);
|
|
141
217
|
|
|
142
218
|
return { config, diagnostics };
|
|
@@ -147,8 +223,9 @@ export function normalizeAndValidateConfig(
|
|
|
147
223
|
*/
|
|
148
224
|
function normalizeAndValidateBuild(
|
|
149
225
|
diagnostics: Diagnostics,
|
|
150
|
-
|
|
151
|
-
rawBuild: Config["build"]
|
|
226
|
+
rawEnv: RawEnvironment,
|
|
227
|
+
rawBuild: Config["build"],
|
|
228
|
+
configPath: string | undefined
|
|
152
229
|
): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
|
|
153
230
|
const { command, cwd, watch_dir, upload, ...rest } = rawBuild;
|
|
154
231
|
const deprecatedUpload: DeprecatedUpload = { ...upload };
|
|
@@ -166,13 +243,13 @@ function normalizeAndValidateBuild(
|
|
|
166
243
|
|
|
167
244
|
deprecated(
|
|
168
245
|
diagnostics,
|
|
169
|
-
|
|
246
|
+
rawEnv,
|
|
170
247
|
"build.upload.format",
|
|
171
248
|
"The format is inferred automatically from the code.",
|
|
172
249
|
true
|
|
173
250
|
);
|
|
174
251
|
|
|
175
|
-
if (
|
|
252
|
+
if (rawEnv.main !== undefined && rawBuild.upload?.main) {
|
|
176
253
|
diagnostics.errors.push(
|
|
177
254
|
`Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.\n` +
|
|
178
255
|
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
@@ -181,7 +258,7 @@ function normalizeAndValidateBuild(
|
|
|
181
258
|
} else {
|
|
182
259
|
deprecated(
|
|
183
260
|
diagnostics,
|
|
184
|
-
|
|
261
|
+
rawEnv,
|
|
185
262
|
"build.upload.main",
|
|
186
263
|
`Delete the \`build.upload.main\` and \`build.upload.dir\` fields.\n` +
|
|
187
264
|
`Then add the top level \`main\` field to your configuration file:\n` +
|
|
@@ -196,24 +273,41 @@ function normalizeAndValidateBuild(
|
|
|
196
273
|
|
|
197
274
|
deprecated(
|
|
198
275
|
diagnostics,
|
|
199
|
-
|
|
276
|
+
rawEnv,
|
|
200
277
|
"build.upload.dir",
|
|
201
278
|
`Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`,
|
|
202
279
|
true
|
|
203
280
|
);
|
|
204
281
|
}
|
|
205
282
|
|
|
206
|
-
return {
|
|
283
|
+
return {
|
|
284
|
+
command,
|
|
285
|
+
watch_dir:
|
|
286
|
+
// - `watch_dir` only matters when `command` is defined, so we apply
|
|
287
|
+
// a default only when `command` is defined
|
|
288
|
+
// - `configPath` will always be defined since `build` can only
|
|
289
|
+
// be configured in `wrangler.toml`, but who knows, that may
|
|
290
|
+
// change in the future, so we do a check anyway
|
|
291
|
+
command
|
|
292
|
+
? configPath
|
|
293
|
+
? path.relative(
|
|
294
|
+
process.cwd(),
|
|
295
|
+
path.join(path.dirname(configPath), watch_dir || "./src")
|
|
296
|
+
)
|
|
297
|
+
: watch_dir || "./src"
|
|
298
|
+
: watch_dir,
|
|
299
|
+
cwd,
|
|
300
|
+
deprecatedUpload,
|
|
301
|
+
};
|
|
207
302
|
}
|
|
208
303
|
|
|
209
304
|
/**
|
|
210
305
|
* Validate the `main` field and return the normalized values.
|
|
211
306
|
*/
|
|
212
307
|
function normalizeAndValidateMainField(
|
|
213
|
-
diagnostics: Diagnostics,
|
|
214
308
|
configPath: string | undefined,
|
|
215
309
|
rawMain: string | undefined,
|
|
216
|
-
deprecatedUpload:
|
|
310
|
+
deprecatedUpload: DeprecatedUpload | undefined
|
|
217
311
|
): string | undefined {
|
|
218
312
|
const configDir = path.dirname(configPath ?? "wrangler.toml");
|
|
219
313
|
if (rawMain !== undefined) {
|
|
@@ -221,13 +315,13 @@ function normalizeAndValidateMainField(
|
|
|
221
315
|
const directory = path.resolve(configDir);
|
|
222
316
|
return path.resolve(directory, rawMain);
|
|
223
317
|
} else {
|
|
224
|
-
|
|
225
|
-
`ERROR: "main" should be a string but got ${JSON.stringify(rawMain)}`
|
|
226
|
-
);
|
|
227
|
-
return;
|
|
318
|
+
return rawMain;
|
|
228
319
|
}
|
|
229
|
-
} else if (deprecatedUpload
|
|
230
|
-
const directory = path.resolve(
|
|
320
|
+
} else if (deprecatedUpload?.main !== undefined) {
|
|
321
|
+
const directory = path.resolve(
|
|
322
|
+
configDir,
|
|
323
|
+
deprecatedUpload?.dir || "./dist"
|
|
324
|
+
);
|
|
231
325
|
return path.resolve(directory, deprecatedUpload.main);
|
|
232
326
|
} else {
|
|
233
327
|
return;
|
|
@@ -239,13 +333,14 @@ function normalizeAndValidateMainField(
|
|
|
239
333
|
*/
|
|
240
334
|
function normalizeAndValidateDev(
|
|
241
335
|
diagnostics: Diagnostics,
|
|
242
|
-
rawDev:
|
|
243
|
-
):
|
|
336
|
+
rawDev: RawDevConfig
|
|
337
|
+
): DevConfig {
|
|
244
338
|
const {
|
|
245
|
-
ip = "
|
|
246
|
-
port
|
|
339
|
+
ip = "localhost",
|
|
340
|
+
port,
|
|
247
341
|
local_protocol = "http",
|
|
248
342
|
upstream_protocol = "https",
|
|
343
|
+
host,
|
|
249
344
|
...rest
|
|
250
345
|
} = rawDev;
|
|
251
346
|
validateAdditionalProperties(diagnostics, "dev", Object.keys(rest), []);
|
|
@@ -257,16 +352,19 @@ function normalizeAndValidateDev(
|
|
|
257
352
|
"dev",
|
|
258
353
|
"local_protocol",
|
|
259
354
|
local_protocol,
|
|
260
|
-
"string"
|
|
355
|
+
"string",
|
|
356
|
+
["http", "https"]
|
|
261
357
|
);
|
|
262
358
|
validateOptionalProperty(
|
|
263
359
|
diagnostics,
|
|
264
360
|
"dev",
|
|
265
361
|
"upstream_protocol",
|
|
266
362
|
upstream_protocol,
|
|
267
|
-
"string"
|
|
363
|
+
"string",
|
|
364
|
+
["http", "https"]
|
|
268
365
|
);
|
|
269
|
-
|
|
366
|
+
validateOptionalProperty(diagnostics, "dev", "host", host, "string");
|
|
367
|
+
return { ip, port, local_protocol, upstream_protocol, host };
|
|
270
368
|
}
|
|
271
369
|
|
|
272
370
|
/**
|
|
@@ -274,7 +372,8 @@ function normalizeAndValidateDev(
|
|
|
274
372
|
*/
|
|
275
373
|
function normalizeAndValidateMigrations(
|
|
276
374
|
diagnostics: Diagnostics,
|
|
277
|
-
rawMigrations: Config["migrations"]
|
|
375
|
+
rawMigrations: Config["migrations"],
|
|
376
|
+
durableObjects: Config["durable_objects"]
|
|
278
377
|
): Config["migrations"] {
|
|
279
378
|
if (!Array.isArray(rawMigrations)) {
|
|
280
379
|
diagnostics.errors.push(
|
|
@@ -302,7 +401,7 @@ function normalizeAndValidateMigrations(
|
|
|
302
401
|
if (migration.renamed_classes !== undefined) {
|
|
303
402
|
if (!Array.isArray(migration.renamed_classes)) {
|
|
304
403
|
diagnostics.errors.push(
|
|
305
|
-
`"migrations[${i}].renamed_classes"
|
|
404
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
306
405
|
migration.renamed_classes
|
|
307
406
|
)}.`
|
|
308
407
|
);
|
|
@@ -315,7 +414,7 @@ function normalizeAndValidateMigrations(
|
|
|
315
414
|
)
|
|
316
415
|
) {
|
|
317
416
|
diagnostics.errors.push(
|
|
318
|
-
`"migrations[${i}].renamed_classes"
|
|
417
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
319
418
|
migration.renamed_classes
|
|
320
419
|
)}.`
|
|
321
420
|
);
|
|
@@ -328,6 +427,45 @@ function normalizeAndValidateMigrations(
|
|
|
328
427
|
"string"
|
|
329
428
|
);
|
|
330
429
|
}
|
|
430
|
+
|
|
431
|
+
if (
|
|
432
|
+
Array.isArray(durableObjects?.bindings) &&
|
|
433
|
+
durableObjects.bindings.length > 0
|
|
434
|
+
) {
|
|
435
|
+
// intrinsic [durable_objects] implies [migrations]
|
|
436
|
+
const exportedDurableObjects = (durableObjects.bindings || []).filter(
|
|
437
|
+
(binding) => !binding.script_name
|
|
438
|
+
);
|
|
439
|
+
if (exportedDurableObjects.length > 0 && rawMigrations.length === 0) {
|
|
440
|
+
if (
|
|
441
|
+
!exportedDurableObjects.some(
|
|
442
|
+
(exportedDurableObject) =>
|
|
443
|
+
typeof exportedDurableObject.class_name !== "string"
|
|
444
|
+
)
|
|
445
|
+
) {
|
|
446
|
+
const durableObjectClassnames = exportedDurableObjects.map(
|
|
447
|
+
(durable) => durable.class_name
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
diagnostics.warnings.push(
|
|
451
|
+
`In wrangler.toml, you have configured [durable_objects] exported by this Worker (${durableObjectClassnames.join(
|
|
452
|
+
", "
|
|
453
|
+
)}), but no [migrations] for them. This may not work as expected until you add a [migrations] section to your wrangler.toml. Add this configuration to your wrangler.toml:
|
|
454
|
+
|
|
455
|
+
\`\`\`
|
|
456
|
+
[[migrations]]
|
|
457
|
+
tag = "v1" # Should be unique for each entry
|
|
458
|
+
new_classes = [${durableObjectClassnames
|
|
459
|
+
.map((name) => `"${name}"`)
|
|
460
|
+
.join(", ")}]
|
|
461
|
+
\`\`\`
|
|
462
|
+
|
|
463
|
+
Refer to https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml for more details.`
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
331
469
|
return rawMigrations;
|
|
332
470
|
}
|
|
333
471
|
}
|
|
@@ -337,39 +475,91 @@ function normalizeAndValidateMigrations(
|
|
|
337
475
|
*/
|
|
338
476
|
function normalizeAndValidateSite(
|
|
339
477
|
diagnostics: Diagnostics,
|
|
340
|
-
|
|
478
|
+
configPath: string | undefined,
|
|
479
|
+
rawConfig: RawConfig,
|
|
480
|
+
mainEntryPoint: string | undefined
|
|
341
481
|
): Config["site"] {
|
|
342
|
-
if (
|
|
343
|
-
const {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
...rest
|
|
349
|
-
} = rawSite;
|
|
350
|
-
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), []);
|
|
482
|
+
if (rawConfig?.site !== undefined) {
|
|
483
|
+
const { bucket, include = [], exclude = [], ...rest } = rawConfig.site;
|
|
484
|
+
|
|
485
|
+
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), [
|
|
486
|
+
"entry-point",
|
|
487
|
+
]);
|
|
351
488
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
489
|
+
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
490
|
+
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
352
491
|
validateOptionalProperty(
|
|
353
492
|
diagnostics,
|
|
354
493
|
"site",
|
|
355
|
-
"
|
|
356
|
-
|
|
494
|
+
"entry-point",
|
|
495
|
+
rawConfig.site["entry-point"],
|
|
357
496
|
"string"
|
|
358
497
|
);
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
498
|
+
|
|
499
|
+
deprecated(
|
|
500
|
+
diagnostics,
|
|
501
|
+
rawConfig,
|
|
502
|
+
`site.entry-point`,
|
|
503
|
+
`Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:\n` +
|
|
504
|
+
`\`\`\`\n` +
|
|
505
|
+
`main = "${path.join(
|
|
506
|
+
String(rawConfig.site["entry-point"]) || "workers-site",
|
|
507
|
+
path.extname(String(rawConfig.site["entry-point"]) || "workers-site")
|
|
508
|
+
? ""
|
|
509
|
+
: "index.js"
|
|
510
|
+
)}"\n` +
|
|
511
|
+
`\`\`\``,
|
|
512
|
+
false,
|
|
513
|
+
undefined,
|
|
514
|
+
"warning"
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
let siteEntryPoint = rawConfig.site["entry-point"];
|
|
518
|
+
|
|
519
|
+
if (!mainEntryPoint && !siteEntryPoint) {
|
|
520
|
+
// this means that we're defaulting to "workers-site"
|
|
521
|
+
// so let's add the deprecation warning
|
|
522
|
+
diagnostics.warnings.push(
|
|
523
|
+
`Because you've defined a [site] configuration, we're defaulting to "workers-site" for the deprecated \`site.entry-point\`field.\n` +
|
|
524
|
+
`Add the top level \`main\` field to your configuration file:\n` +
|
|
525
|
+
`\`\`\`\n` +
|
|
526
|
+
`main = "workers-site/index.js"\n` +
|
|
527
|
+
`\`\`\``
|
|
528
|
+
);
|
|
529
|
+
siteEntryPoint = "workers-site";
|
|
530
|
+
} else if (mainEntryPoint && siteEntryPoint) {
|
|
531
|
+
diagnostics.errors.push(
|
|
532
|
+
`Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.\n` +
|
|
533
|
+
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
534
|
+
`Delete the deprecated \`site.entry-point\` field from your config.`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (configPath && siteEntryPoint) {
|
|
539
|
+
// rewrite the path to be relative to the working directory
|
|
540
|
+
siteEntryPoint = path.relative(
|
|
541
|
+
process.cwd(),
|
|
542
|
+
path.join(path.dirname(configPath), siteEntryPoint)
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
bucket,
|
|
548
|
+
"entry-point": siteEntryPoint,
|
|
549
|
+
include,
|
|
550
|
+
exclude,
|
|
551
|
+
};
|
|
362
552
|
}
|
|
363
553
|
return undefined;
|
|
364
554
|
}
|
|
365
555
|
|
|
366
556
|
/**
|
|
367
|
-
* Map the paths of the `wasm_modules` or `
|
|
557
|
+
* Map the paths of the `wasm_modules`, `text_blobs` or `data_blobs` configuration to be relative to the current working directory.
|
|
368
558
|
*/
|
|
369
559
|
function normalizeAndValidateModulePaths(
|
|
370
560
|
diagnostics: Diagnostics,
|
|
371
561
|
configPath: string | undefined,
|
|
372
|
-
field: "wasm_modules" | "text_blobs",
|
|
562
|
+
field: "wasm_modules" | "text_blobs" | "data_blobs",
|
|
373
563
|
rawMapping: Record<string, string> | undefined
|
|
374
564
|
): Record<string, string> | undefined {
|
|
375
565
|
if (rawMapping === undefined) {
|
|
@@ -392,31 +582,147 @@ function normalizeAndValidateModulePaths(
|
|
|
392
582
|
return mapping;
|
|
393
583
|
}
|
|
394
584
|
|
|
585
|
+
/**
|
|
586
|
+
* Check whether a value has the shape of a route, which can be a string
|
|
587
|
+
* or an object that looks like {pattern: string, zone_id: string }
|
|
588
|
+
*/
|
|
589
|
+
function isValidRouteValue(item: unknown): boolean {
|
|
590
|
+
if (!item) {
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
if (typeof item === "string") {
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
if (typeof item === "object") {
|
|
597
|
+
if (!hasProperty(item, "pattern") || typeof item.pattern !== "string") {
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const otherKeys = Object.keys(item).length - 1; // minus one to subtract "pattern"
|
|
602
|
+
|
|
603
|
+
const hasZoneId =
|
|
604
|
+
hasProperty(item, "zone_id") && typeof item.zone_id === "string";
|
|
605
|
+
const hasZoneName =
|
|
606
|
+
hasProperty(item, "zone_name") && typeof item.zone_name === "string";
|
|
607
|
+
const hasCustomDomainFlag =
|
|
608
|
+
hasProperty(item, "custom_domain") &&
|
|
609
|
+
typeof item.custom_domain === "boolean";
|
|
610
|
+
|
|
611
|
+
if (otherKeys === 2 && hasCustomDomainFlag && (hasZoneId || hasZoneName)) {
|
|
612
|
+
return true;
|
|
613
|
+
} else if (
|
|
614
|
+
otherKeys === 1 &&
|
|
615
|
+
(hasZoneId || hasZoneName || hasCustomDomainFlag)
|
|
616
|
+
) {
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Validate that the field is a route.
|
|
625
|
+
*/
|
|
626
|
+
const isRoute: ValidatorFn = (diagnostics, field, value) => {
|
|
627
|
+
if (value !== undefined && !isValidRouteValue(value)) {
|
|
628
|
+
diagnostics.errors.push(
|
|
629
|
+
`Expected "${field}" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got ${JSON.stringify(
|
|
630
|
+
value
|
|
631
|
+
)}.`
|
|
632
|
+
);
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
return true;
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Validate that the field is an array of routes.
|
|
640
|
+
*/
|
|
641
|
+
const isRouteArray: ValidatorFn = (diagnostics, field, value) => {
|
|
642
|
+
if (value === undefined) {
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
645
|
+
if (!Array.isArray(value)) {
|
|
646
|
+
diagnostics.errors.push(
|
|
647
|
+
`Expected "${field}" to be an array but got ${JSON.stringify(value)}.`
|
|
648
|
+
);
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
const invalidRoutes = [];
|
|
652
|
+
for (const item of value) {
|
|
653
|
+
if (!isValidRouteValue(item)) {
|
|
654
|
+
invalidRoutes.push(item);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (invalidRoutes.length > 0) {
|
|
658
|
+
diagnostics.errors.push(
|
|
659
|
+
`Expected "${field}" to be an array of either strings or objects with the shape { pattern, custom_domain, zone_id | zone_name }, but these weren't valid: ${JSON.stringify(
|
|
660
|
+
invalidRoutes,
|
|
661
|
+
null,
|
|
662
|
+
2
|
|
663
|
+
)}.`
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
return invalidRoutes.length === 0;
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
function validateRoute(
|
|
670
|
+
diagnostics: Diagnostics,
|
|
671
|
+
topLevelEnv: Environment | undefined,
|
|
672
|
+
rawEnv: RawEnvironment
|
|
673
|
+
): Config["route"] {
|
|
674
|
+
return inheritable(
|
|
675
|
+
diagnostics,
|
|
676
|
+
topLevelEnv,
|
|
677
|
+
rawEnv,
|
|
678
|
+
"route",
|
|
679
|
+
isRoute,
|
|
680
|
+
undefined
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function validateRoutes(
|
|
685
|
+
diagnostics: Diagnostics,
|
|
686
|
+
topLevelEnv: Environment | undefined,
|
|
687
|
+
rawEnv: RawEnvironment
|
|
688
|
+
): Config["routes"] {
|
|
689
|
+
return inheritable(
|
|
690
|
+
diagnostics,
|
|
691
|
+
topLevelEnv,
|
|
692
|
+
rawEnv,
|
|
693
|
+
"routes",
|
|
694
|
+
all(isRouteArray, isMutuallyExclusiveWith(rawEnv, "route")),
|
|
695
|
+
undefined
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
|
|
395
699
|
/**
|
|
396
700
|
* Validate top-level environment configuration and return the normalized values.
|
|
397
701
|
*/
|
|
398
702
|
function normalizeAndValidateEnvironment(
|
|
399
703
|
diagnostics: Diagnostics,
|
|
400
|
-
|
|
401
|
-
|
|
704
|
+
configPath: string | undefined,
|
|
705
|
+
topLevelEnv: RawEnvironment
|
|
402
706
|
): Environment;
|
|
403
707
|
/**
|
|
404
708
|
* Validate the named environment configuration and return the normalized values.
|
|
405
709
|
*/
|
|
406
710
|
function normalizeAndValidateEnvironment(
|
|
407
711
|
diagnostics: Diagnostics,
|
|
712
|
+
configPath: string | undefined,
|
|
408
713
|
rawEnv: RawEnvironment,
|
|
409
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
410
714
|
envName: string,
|
|
411
|
-
|
|
715
|
+
topLevelEnv: Environment,
|
|
716
|
+
isLegacyEnv: boolean,
|
|
412
717
|
rawConfig: RawConfig
|
|
413
718
|
): Environment;
|
|
414
719
|
function normalizeAndValidateEnvironment(
|
|
415
720
|
diagnostics: Diagnostics,
|
|
721
|
+
configPath: string | undefined,
|
|
416
722
|
rawEnv: RawEnvironment,
|
|
417
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
418
723
|
envName = "top level",
|
|
419
|
-
|
|
724
|
+
topLevelEnv?: Environment | undefined,
|
|
725
|
+
isLegacyEnv?: boolean,
|
|
420
726
|
rawConfig?: RawConfig | undefined
|
|
421
727
|
): Environment {
|
|
422
728
|
deprecated(
|
|
@@ -433,66 +739,48 @@ function normalizeAndValidateEnvironment(
|
|
|
433
739
|
diagnostics,
|
|
434
740
|
rawEnv,
|
|
435
741
|
"experimental_services",
|
|
436
|
-
`The "experimental_services" field is no longer supported.
|
|
437
|
-
"```\n" +
|
|
438
|
-
TOML.stringify({
|
|
439
|
-
unsafe: {
|
|
440
|
-
bindings: (rawEnv?.experimental_services || []).map(
|
|
441
|
-
(serviceDefinition) => {
|
|
442
|
-
return {
|
|
443
|
-
name: serviceDefinition.name,
|
|
444
|
-
type: "service",
|
|
445
|
-
service: serviceDefinition.service,
|
|
446
|
-
environment: serviceDefinition.environment,
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
),
|
|
450
|
-
},
|
|
451
|
-
}) +
|
|
452
|
-
"```",
|
|
742
|
+
`The "experimental_services" field is no longer supported. Simply rename the [experimental_services] field to [services].`,
|
|
453
743
|
true
|
|
454
744
|
);
|
|
455
745
|
|
|
456
746
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
747
|
+
experimental(diagnostics, rawEnv, "services");
|
|
457
748
|
|
|
458
|
-
const route =
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
isString,
|
|
464
|
-
undefined
|
|
465
|
-
);
|
|
466
|
-
const routes = inheritable(
|
|
749
|
+
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
750
|
+
|
|
751
|
+
const routes = validateRoutes(diagnostics, topLevelEnv, rawEnv);
|
|
752
|
+
|
|
753
|
+
const workers_dev = inheritable(
|
|
467
754
|
diagnostics,
|
|
468
|
-
|
|
755
|
+
topLevelEnv,
|
|
469
756
|
rawEnv,
|
|
470
|
-
"
|
|
471
|
-
|
|
757
|
+
"workers_dev",
|
|
758
|
+
isBoolean,
|
|
472
759
|
undefined
|
|
473
760
|
);
|
|
474
|
-
|
|
761
|
+
|
|
762
|
+
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
475
763
|
diagnostics,
|
|
476
|
-
config,
|
|
477
764
|
rawEnv,
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
!(routes || route)
|
|
765
|
+
rawEnv.build ?? topLevelEnv?.build ?? {},
|
|
766
|
+
configPath
|
|
481
767
|
);
|
|
482
768
|
|
|
483
769
|
const environment: Environment = {
|
|
484
770
|
// Inherited fields
|
|
485
|
-
account_id:
|
|
771
|
+
account_id: inheritableInLegacyEnvironments(
|
|
486
772
|
diagnostics,
|
|
487
|
-
|
|
773
|
+
isLegacyEnv,
|
|
774
|
+
topLevelEnv,
|
|
488
775
|
rawEnv,
|
|
489
776
|
"account_id",
|
|
490
777
|
isString,
|
|
778
|
+
undefined,
|
|
491
779
|
undefined
|
|
492
780
|
),
|
|
493
781
|
compatibility_date: inheritable(
|
|
494
782
|
diagnostics,
|
|
495
|
-
|
|
783
|
+
topLevelEnv,
|
|
496
784
|
rawEnv,
|
|
497
785
|
"compatibility_date",
|
|
498
786
|
isString,
|
|
@@ -500,7 +788,7 @@ function normalizeAndValidateEnvironment(
|
|
|
500
788
|
),
|
|
501
789
|
compatibility_flags: inheritable(
|
|
502
790
|
diagnostics,
|
|
503
|
-
|
|
791
|
+
topLevelEnv,
|
|
504
792
|
rawEnv,
|
|
505
793
|
"compatibility_flags",
|
|
506
794
|
isStringArray,
|
|
@@ -508,7 +796,7 @@ function normalizeAndValidateEnvironment(
|
|
|
508
796
|
),
|
|
509
797
|
jsx_factory: inheritable(
|
|
510
798
|
diagnostics,
|
|
511
|
-
|
|
799
|
+
topLevelEnv,
|
|
512
800
|
rawEnv,
|
|
513
801
|
"jsx_factory",
|
|
514
802
|
isString,
|
|
@@ -516,25 +804,52 @@ function normalizeAndValidateEnvironment(
|
|
|
516
804
|
),
|
|
517
805
|
jsx_fragment: inheritable(
|
|
518
806
|
diagnostics,
|
|
519
|
-
|
|
807
|
+
topLevelEnv,
|
|
520
808
|
rawEnv,
|
|
521
809
|
"jsx_fragment",
|
|
522
810
|
isString,
|
|
523
811
|
"React.Fragment"
|
|
524
812
|
),
|
|
813
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
814
|
+
diagnostics,
|
|
815
|
+
topLevelEnv,
|
|
816
|
+
rawEnv,
|
|
817
|
+
configPath
|
|
818
|
+
),
|
|
525
819
|
rules: validateAndNormalizeRules(
|
|
526
820
|
diagnostics,
|
|
527
|
-
|
|
821
|
+
topLevelEnv,
|
|
528
822
|
rawEnv,
|
|
529
|
-
|
|
823
|
+
deprecatedUpload?.rules,
|
|
530
824
|
envName
|
|
531
825
|
),
|
|
532
|
-
name:
|
|
826
|
+
name: inheritableInLegacyEnvironments(
|
|
827
|
+
diagnostics,
|
|
828
|
+
isLegacyEnv,
|
|
829
|
+
topLevelEnv,
|
|
830
|
+
rawEnv,
|
|
831
|
+
"name",
|
|
832
|
+
isValidName,
|
|
833
|
+
appendEnvName(envName),
|
|
834
|
+
undefined
|
|
835
|
+
),
|
|
836
|
+
main: normalizeAndValidateMainField(
|
|
837
|
+
configPath,
|
|
838
|
+
inheritable(
|
|
839
|
+
diagnostics,
|
|
840
|
+
topLevelEnv,
|
|
841
|
+
rawEnv,
|
|
842
|
+
"main",
|
|
843
|
+
isString,
|
|
844
|
+
undefined
|
|
845
|
+
),
|
|
846
|
+
deprecatedUpload
|
|
847
|
+
),
|
|
533
848
|
route,
|
|
534
849
|
routes,
|
|
535
850
|
triggers: inheritable(
|
|
536
851
|
diagnostics,
|
|
537
|
-
|
|
852
|
+
topLevelEnv,
|
|
538
853
|
rawEnv,
|
|
539
854
|
"triggers",
|
|
540
855
|
isObjectWith("crons"),
|
|
@@ -542,17 +857,18 @@ function normalizeAndValidateEnvironment(
|
|
|
542
857
|
),
|
|
543
858
|
usage_model: inheritable(
|
|
544
859
|
diagnostics,
|
|
545
|
-
|
|
860
|
+
topLevelEnv,
|
|
546
861
|
rawEnv,
|
|
547
862
|
"usage_model",
|
|
548
863
|
isOneOf("bundled", "unbound"),
|
|
549
864
|
undefined
|
|
550
865
|
),
|
|
866
|
+
build,
|
|
551
867
|
workers_dev,
|
|
552
868
|
// Not inherited fields
|
|
553
869
|
vars: notInheritable(
|
|
554
870
|
diagnostics,
|
|
555
|
-
|
|
871
|
+
topLevelEnv,
|
|
556
872
|
rawConfig,
|
|
557
873
|
rawEnv,
|
|
558
874
|
envName,
|
|
@@ -562,7 +878,7 @@ function normalizeAndValidateEnvironment(
|
|
|
562
878
|
),
|
|
563
879
|
durable_objects: notInheritable(
|
|
564
880
|
diagnostics,
|
|
565
|
-
|
|
881
|
+
topLevelEnv,
|
|
566
882
|
rawConfig,
|
|
567
883
|
rawEnv,
|
|
568
884
|
envName,
|
|
@@ -574,7 +890,7 @@ function normalizeAndValidateEnvironment(
|
|
|
574
890
|
),
|
|
575
891
|
kv_namespaces: notInheritable(
|
|
576
892
|
diagnostics,
|
|
577
|
-
|
|
893
|
+
topLevelEnv,
|
|
578
894
|
rawConfig,
|
|
579
895
|
rawEnv,
|
|
580
896
|
envName,
|
|
@@ -584,7 +900,7 @@ function normalizeAndValidateEnvironment(
|
|
|
584
900
|
),
|
|
585
901
|
r2_buckets: notInheritable(
|
|
586
902
|
diagnostics,
|
|
587
|
-
|
|
903
|
+
topLevelEnv,
|
|
588
904
|
rawConfig,
|
|
589
905
|
rawEnv,
|
|
590
906
|
envName,
|
|
@@ -592,9 +908,19 @@ function normalizeAndValidateEnvironment(
|
|
|
592
908
|
validateBindingArray(envName, validateR2Binding),
|
|
593
909
|
[]
|
|
594
910
|
),
|
|
911
|
+
services: notInheritable(
|
|
912
|
+
diagnostics,
|
|
913
|
+
topLevelEnv,
|
|
914
|
+
rawConfig,
|
|
915
|
+
rawEnv,
|
|
916
|
+
envName,
|
|
917
|
+
"services",
|
|
918
|
+
validateBindingArray(envName, validateServiceBinding),
|
|
919
|
+
[]
|
|
920
|
+
),
|
|
595
921
|
unsafe: notInheritable(
|
|
596
922
|
diagnostics,
|
|
597
|
-
|
|
923
|
+
topLevelEnv,
|
|
598
924
|
rawConfig,
|
|
599
925
|
rawEnv,
|
|
600
926
|
envName,
|
|
@@ -605,27 +931,66 @@ function normalizeAndValidateEnvironment(
|
|
|
605
931
|
}
|
|
606
932
|
),
|
|
607
933
|
zone_id: rawEnv.zone_id,
|
|
934
|
+
minify: inheritable(
|
|
935
|
+
diagnostics,
|
|
936
|
+
topLevelEnv,
|
|
937
|
+
rawEnv,
|
|
938
|
+
"minify",
|
|
939
|
+
isBoolean,
|
|
940
|
+
undefined
|
|
941
|
+
),
|
|
942
|
+
node_compat: inheritable(
|
|
943
|
+
diagnostics,
|
|
944
|
+
topLevelEnv,
|
|
945
|
+
rawEnv,
|
|
946
|
+
"node_compat",
|
|
947
|
+
isBoolean,
|
|
948
|
+
undefined
|
|
949
|
+
),
|
|
608
950
|
};
|
|
609
951
|
|
|
610
952
|
return environment;
|
|
611
953
|
}
|
|
612
954
|
|
|
955
|
+
function validateAndNormalizeTsconfig(
|
|
956
|
+
diagnostics: Diagnostics,
|
|
957
|
+
topLevelEnv: Environment | undefined,
|
|
958
|
+
rawEnv: RawEnvironment,
|
|
959
|
+
configPath: string | undefined
|
|
960
|
+
) {
|
|
961
|
+
const tsconfig = inheritable(
|
|
962
|
+
diagnostics,
|
|
963
|
+
topLevelEnv,
|
|
964
|
+
rawEnv,
|
|
965
|
+
"tsconfig",
|
|
966
|
+
isString,
|
|
967
|
+
undefined
|
|
968
|
+
);
|
|
969
|
+
|
|
970
|
+
return configPath && tsconfig
|
|
971
|
+
? path.relative(
|
|
972
|
+
process.cwd(),
|
|
973
|
+
path.join(path.dirname(configPath), tsconfig)
|
|
974
|
+
)
|
|
975
|
+
: tsconfig;
|
|
976
|
+
}
|
|
977
|
+
|
|
613
978
|
const validateAndNormalizeRules = (
|
|
614
979
|
diagnostics: Diagnostics,
|
|
615
|
-
|
|
980
|
+
topLevelEnv: Environment | undefined,
|
|
616
981
|
rawEnv: RawEnvironment,
|
|
617
982
|
deprecatedRules: Rule[] | undefined,
|
|
618
983
|
envName: string
|
|
619
984
|
): Rule[] => {
|
|
620
|
-
if (
|
|
985
|
+
if (topLevelEnv === undefined) {
|
|
621
986
|
// Only create errors/warnings for the top-level environment
|
|
622
987
|
if (rawEnv.rules && deprecatedRules) {
|
|
623
988
|
diagnostics.errors.push(
|
|
624
|
-
`
|
|
989
|
+
`You cannot configure both [rules] and [build.upload.rules] in your wrangler.toml. Delete the \`build.upload\` section.`
|
|
625
990
|
);
|
|
626
991
|
} else if (deprecatedRules) {
|
|
627
992
|
diagnostics.warnings.push(
|
|
628
|
-
`
|
|
993
|
+
`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` +
|
|
629
994
|
"```\n" +
|
|
630
995
|
TOML.stringify({ rules: deprecatedRules }) +
|
|
631
996
|
"```"
|
|
@@ -635,7 +1000,7 @@ const validateAndNormalizeRules = (
|
|
|
635
1000
|
|
|
636
1001
|
return inheritable(
|
|
637
1002
|
diagnostics,
|
|
638
|
-
|
|
1003
|
+
topLevelEnv,
|
|
639
1004
|
rawEnv,
|
|
640
1005
|
"rules",
|
|
641
1006
|
validateRules(envName),
|
|
@@ -671,7 +1036,9 @@ const validateRules =
|
|
|
671
1036
|
|
|
672
1037
|
const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
673
1038
|
if (typeof value !== "object" || value === null) {
|
|
674
|
-
diagnostics.errors.push(
|
|
1039
|
+
diagnostics.errors.push(
|
|
1040
|
+
`"${field}" should be an object but got ${JSON.stringify(value)}.`
|
|
1041
|
+
);
|
|
675
1042
|
return false;
|
|
676
1043
|
}
|
|
677
1044
|
// Rules must have a type string and glob string array, and optionally a fallthrough boolean.
|
|
@@ -688,7 +1055,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
688
1055
|
])
|
|
689
1056
|
) {
|
|
690
1057
|
diagnostics.errors.push(
|
|
691
|
-
`
|
|
1058
|
+
`bindings should have a string "type" field, which contains one of "ESModule", "CommonJS", "CompiledWasm", "Text", or "Data".`
|
|
692
1059
|
);
|
|
693
1060
|
isValid = false;
|
|
694
1061
|
}
|
|
@@ -699,7 +1066,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
699
1066
|
|
|
700
1067
|
if (!isOptionalProperty(rule, "fallthrough", "boolean")) {
|
|
701
1068
|
diagnostics.errors.push(
|
|
702
|
-
`
|
|
1069
|
+
`the field "fallthrough", when present, should be a boolean.`
|
|
703
1070
|
);
|
|
704
1071
|
isValid = false;
|
|
705
1072
|
}
|
|
@@ -796,7 +1163,7 @@ const validateBindingsProperty =
|
|
|
796
1163
|
diagnostics.warnings.push(
|
|
797
1164
|
`The following bindings are at the top level, but not on "env.${envName}".\n` +
|
|
798
1165
|
`This is not what you probably want, since "${field}" configuration is not inherited by environments.\n` +
|
|
799
|
-
`Please add a binding for each to "${fieldPath}.bindings"
|
|
1166
|
+
`Please add a binding for each to "${fieldPath}.bindings":\n` +
|
|
800
1167
|
missingBindings.map((name) => `- ${name}`).join("\n")
|
|
801
1168
|
);
|
|
802
1169
|
}
|
|
@@ -805,42 +1172,48 @@ const validateBindingsProperty =
|
|
|
805
1172
|
return isValid;
|
|
806
1173
|
};
|
|
807
1174
|
|
|
808
|
-
/**
|
|
809
|
-
* Get the names of the bindings collection in `value`.
|
|
810
|
-
*/
|
|
811
|
-
const getBindingNames = (value: unknown): string[] =>
|
|
812
|
-
((value as { bindings: { name: string }[] })?.bindings ?? []).map(
|
|
813
|
-
(binding) => binding.name
|
|
814
|
-
);
|
|
815
|
-
|
|
816
1175
|
/**
|
|
817
1176
|
* Check that the given field is a valid "durable_object" binding object.
|
|
818
1177
|
*/
|
|
819
1178
|
const validateDurableObjectBinding: ValidatorFn = (
|
|
820
1179
|
diagnostics,
|
|
821
|
-
|
|
1180
|
+
field,
|
|
822
1181
|
value
|
|
823
1182
|
) => {
|
|
824
1183
|
if (typeof value !== "object" || value === null) {
|
|
825
|
-
diagnostics.errors.push(
|
|
1184
|
+
diagnostics.errors.push(
|
|
1185
|
+
`Expected "${field}" to be an object but got ${JSON.stringify(value)}`
|
|
1186
|
+
);
|
|
826
1187
|
return false;
|
|
827
1188
|
}
|
|
828
1189
|
|
|
829
|
-
// Durable Object bindings must have a name and class_name, and optionally a script_name.
|
|
1190
|
+
// Durable Object bindings must have a name and class_name, and optionally a script_name and an environment.
|
|
830
1191
|
let isValid = true;
|
|
831
1192
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
832
|
-
diagnostics.errors.push(
|
|
833
|
-
`ERROR: bindings should have a string "name" field.`
|
|
834
|
-
);
|
|
1193
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
835
1194
|
isValid = false;
|
|
836
1195
|
}
|
|
837
1196
|
if (!isRequiredProperty(value, "class_name", "string")) {
|
|
838
|
-
diagnostics.errors.push(`
|
|
1197
|
+
diagnostics.errors.push(`binding should have a string "class_name" field.`);
|
|
839
1198
|
isValid = false;
|
|
840
1199
|
}
|
|
841
1200
|
if (!isOptionalProperty(value, "script_name", "string")) {
|
|
842
1201
|
diagnostics.errors.push(
|
|
843
|
-
`
|
|
1202
|
+
`the field "script_name", when present, should be a string.`
|
|
1203
|
+
);
|
|
1204
|
+
isValid = false;
|
|
1205
|
+
}
|
|
1206
|
+
// environment requires a script_name
|
|
1207
|
+
if (!isOptionalProperty(value, "environment", "string")) {
|
|
1208
|
+
diagnostics.errors.push(
|
|
1209
|
+
`the field "environment", when present, should be a string.`
|
|
1210
|
+
);
|
|
1211
|
+
isValid = false;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
if ("environment" in value && !("script_name" in value)) {
|
|
1215
|
+
diagnostics.errors.push(
|
|
1216
|
+
`binding should have a "script_name" field if "environment" is present.`
|
|
844
1217
|
);
|
|
845
1218
|
isValid = false;
|
|
846
1219
|
}
|
|
@@ -853,24 +1226,31 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
853
1226
|
*
|
|
854
1227
|
* TODO: further validation of known unsafe bindings.
|
|
855
1228
|
*/
|
|
856
|
-
const validateUnsafeBinding: ValidatorFn = (diagnostics,
|
|
1229
|
+
const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
857
1230
|
if (typeof value !== "object" || value === null) {
|
|
858
|
-
diagnostics.errors.push(
|
|
1231
|
+
diagnostics.errors.push(
|
|
1232
|
+
`Expected ${field} to be an object but got ${JSON.stringify(value)}.`
|
|
1233
|
+
);
|
|
859
1234
|
return false;
|
|
860
1235
|
}
|
|
861
1236
|
|
|
862
1237
|
let isValid = true;
|
|
863
1238
|
// Unsafe bindings must have a name and type.
|
|
864
1239
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
865
|
-
diagnostics.errors.push(`
|
|
1240
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
866
1241
|
isValid = false;
|
|
867
1242
|
}
|
|
868
1243
|
if (isRequiredProperty(value, "type", "string")) {
|
|
869
1244
|
const safeBindings = [
|
|
870
1245
|
"plain_text",
|
|
871
1246
|
"json",
|
|
1247
|
+
"wasm_module",
|
|
1248
|
+
"data_blob",
|
|
1249
|
+
"text_blob",
|
|
872
1250
|
"kv_namespace",
|
|
873
1251
|
"durable_object_namespace",
|
|
1252
|
+
"r2_bucket",
|
|
1253
|
+
"service",
|
|
874
1254
|
];
|
|
875
1255
|
|
|
876
1256
|
if (safeBindings.includes(value.type)) {
|
|
@@ -881,7 +1261,7 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, _field, value) => {
|
|
|
881
1261
|
);
|
|
882
1262
|
}
|
|
883
1263
|
} else {
|
|
884
|
-
diagnostics.errors.push(`
|
|
1264
|
+
diagnostics.errors.push(`binding should have a string "type" field.`);
|
|
885
1265
|
isValid = false;
|
|
886
1266
|
}
|
|
887
1267
|
return isValid;
|
|
@@ -981,7 +1361,7 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
981
1361
|
const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
982
1362
|
if (typeof value !== "object" || value === null) {
|
|
983
1363
|
diagnostics.errors.push(
|
|
984
|
-
`"
|
|
1364
|
+
`"r2_buckets" bindings should be objects, but got ${JSON.stringify(
|
|
985
1365
|
value
|
|
986
1366
|
)}`
|
|
987
1367
|
);
|
|
@@ -1015,3 +1395,136 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1015
1395
|
}
|
|
1016
1396
|
return isValid;
|
|
1017
1397
|
};
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Check that bindings whose names might conflict, don't.
|
|
1401
|
+
*
|
|
1402
|
+
* We don't want to have, for example, a KV namespace named "DATA"
|
|
1403
|
+
* and a Durable Object also named "DATA". Then it would be ambiguous
|
|
1404
|
+
* what exactly would live at `env.DATA` (or in the case of service-workers,
|
|
1405
|
+
* the `DATA` global).
|
|
1406
|
+
*/
|
|
1407
|
+
const validateBindingsHaveUniqueNames = (
|
|
1408
|
+
diagnostics: Diagnostics,
|
|
1409
|
+
{
|
|
1410
|
+
durable_objects,
|
|
1411
|
+
kv_namespaces,
|
|
1412
|
+
r2_buckets,
|
|
1413
|
+
text_blobs,
|
|
1414
|
+
unsafe,
|
|
1415
|
+
vars,
|
|
1416
|
+
wasm_modules,
|
|
1417
|
+
data_blobs,
|
|
1418
|
+
}: Partial<Config>
|
|
1419
|
+
): boolean => {
|
|
1420
|
+
let hasDuplicates = false;
|
|
1421
|
+
|
|
1422
|
+
const bindingsGroupedByType = {
|
|
1423
|
+
"Durable Object": getBindingNames(durable_objects),
|
|
1424
|
+
"KV Namespace": getBindingNames(kv_namespaces),
|
|
1425
|
+
"R2 Bucket": getBindingNames(r2_buckets),
|
|
1426
|
+
"Text Blob": getBindingNames(text_blobs),
|
|
1427
|
+
Unsafe: getBindingNames(unsafe),
|
|
1428
|
+
"Environment Variable": getBindingNames(vars),
|
|
1429
|
+
"WASM Module": getBindingNames(wasm_modules),
|
|
1430
|
+
"Data Blob": getBindingNames(data_blobs),
|
|
1431
|
+
} as Record<string, string[]>;
|
|
1432
|
+
|
|
1433
|
+
const bindingsGroupedByName: Record<string, string[]> = {};
|
|
1434
|
+
|
|
1435
|
+
for (const bindingType in bindingsGroupedByType) {
|
|
1436
|
+
const bindingNames = bindingsGroupedByType[bindingType];
|
|
1437
|
+
|
|
1438
|
+
for (const bindingName of bindingNames) {
|
|
1439
|
+
if (!(bindingName in bindingsGroupedByName)) {
|
|
1440
|
+
bindingsGroupedByName[bindingName] = [];
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
bindingsGroupedByName[bindingName].push(bindingType);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
for (const bindingName in bindingsGroupedByName) {
|
|
1448
|
+
const bindingTypes = bindingsGroupedByName[bindingName];
|
|
1449
|
+
if (bindingTypes.length < 2) {
|
|
1450
|
+
// there's only one (or zero) binding(s) with this name, which is fine, actually
|
|
1451
|
+
continue;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
hasDuplicates = true;
|
|
1455
|
+
|
|
1456
|
+
// there's two types of duplicates we want to look for:
|
|
1457
|
+
// - bindings with the same name of the same type (e.g. two Durable Objects both named "OBJ")
|
|
1458
|
+
// - bindings with the same name of different types (a KV namespace and DO both named "DATA")
|
|
1459
|
+
|
|
1460
|
+
const sameType = bindingTypes
|
|
1461
|
+
// filter once to find duplicate binding types
|
|
1462
|
+
.filter((type, i) => bindingTypes.indexOf(type) !== i)
|
|
1463
|
+
// filter twice to only get _unique_ duplicate binding types
|
|
1464
|
+
.filter(
|
|
1465
|
+
(type, i, duplicateBindingTypes) =>
|
|
1466
|
+
duplicateBindingTypes.indexOf(type) === i
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
const differentTypes = bindingTypes.filter(
|
|
1470
|
+
(type, i) => bindingTypes.indexOf(type) === i
|
|
1471
|
+
);
|
|
1472
|
+
|
|
1473
|
+
if (differentTypes.length > 1) {
|
|
1474
|
+
// we have multiple different types using the same name
|
|
1475
|
+
diagnostics.errors.push(
|
|
1476
|
+
`${bindingName} assigned to ${ENGLISH.format(differentTypes)} bindings.`
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
sameType.forEach((bindingType) => {
|
|
1481
|
+
diagnostics.errors.push(
|
|
1482
|
+
`${bindingName} assigned to multiple ${bindingType} bindings.`
|
|
1483
|
+
);
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
if (hasDuplicates) {
|
|
1488
|
+
const problem =
|
|
1489
|
+
"Bindings must have unique names, so that they can all be referenced in the worker.";
|
|
1490
|
+
const resolution = "Please change your bindings to have unique names.";
|
|
1491
|
+
diagnostics.errors.push(`${problem}\n${resolution}`);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
return !hasDuplicates;
|
|
1495
|
+
};
|
|
1496
|
+
const validateServiceBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
1497
|
+
if (typeof value !== "object" || value === null) {
|
|
1498
|
+
diagnostics.errors.push(
|
|
1499
|
+
`"services" bindings should be objects, but got ${JSON.stringify(value)}`
|
|
1500
|
+
);
|
|
1501
|
+
return false;
|
|
1502
|
+
}
|
|
1503
|
+
let isValid = true;
|
|
1504
|
+
// Service bindings must have a binding, service, and environment.
|
|
1505
|
+
if (!isRequiredProperty(value, "binding", "string")) {
|
|
1506
|
+
diagnostics.errors.push(
|
|
1507
|
+
`"${field}" bindings should have a string "binding" field but got ${JSON.stringify(
|
|
1508
|
+
value
|
|
1509
|
+
)}.`
|
|
1510
|
+
);
|
|
1511
|
+
isValid = false;
|
|
1512
|
+
}
|
|
1513
|
+
if (!isRequiredProperty(value, "service", "string")) {
|
|
1514
|
+
diagnostics.errors.push(
|
|
1515
|
+
`"${field}" bindings should have a string "service" field but got ${JSON.stringify(
|
|
1516
|
+
value
|
|
1517
|
+
)}.`
|
|
1518
|
+
);
|
|
1519
|
+
isValid = false;
|
|
1520
|
+
}
|
|
1521
|
+
if (!isOptionalProperty(value, "environment", "string")) {
|
|
1522
|
+
diagnostics.errors.push(
|
|
1523
|
+
`"${field}" bindings should have a string "environment" field but got ${JSON.stringify(
|
|
1524
|
+
value
|
|
1525
|
+
)}.`
|
|
1526
|
+
);
|
|
1527
|
+
isValid = false;
|
|
1528
|
+
}
|
|
1529
|
+
return isValid;
|
|
1530
|
+
};
|