wrangler 0.0.0-e3cab74 → 0.0.0-e3e3243
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 +1 -1
- package/bin/wrangler.js +10 -1
- package/miniflare-dist/index.mjs +79 -0
- package/miniflare-dist/index.mjs.map +7 -0
- package/package.json +10 -7
- package/pages/functions/filepath-routing.test.ts +125 -25
- package/pages/functions/filepath-routing.ts +6 -3
- package/src/__tests__/configuration.test.ts +959 -324
- package/src/__tests__/dev.test.tsx +512 -84
- package/src/__tests__/guess-worker-format.test.ts +19 -17
- package/src/__tests__/helpers/mock-account-id.ts +22 -4
- package/src/__tests__/helpers/mock-cfetch.ts +3 -3
- package/src/__tests__/helpers/mock-console.ts +17 -9
- package/src/__tests__/helpers/mock-kv.ts +9 -16
- package/src/__tests__/helpers/mock-stdin.ts +103 -0
- package/src/__tests__/helpers/run-in-tmp.ts +3 -0
- package/src/__tests__/https-options.test.ts +127 -0
- package/src/__tests__/index.test.ts +128 -11
- package/src/__tests__/jest.setup.ts +16 -4
- package/src/__tests__/kv.test.ts +364 -125
- package/src/__tests__/logout.test.ts +15 -13
- package/src/__tests__/pages.test.ts +82 -0
- package/src/__tests__/publish.test.ts +1838 -735
- package/src/__tests__/r2.test.ts +4 -4
- package/src/__tests__/route.test.ts +45 -0
- package/src/__tests__/secret.test.ts +167 -68
- package/src/__tests__/tail.test.ts +2 -4
- package/src/__tests__/whoami.test.tsx +21 -7
- package/src/bundle.ts +27 -5
- package/src/cfetch/internal.ts +11 -5
- package/src/config/README.md +6 -6
- package/src/config/config.ts +54 -101
- package/src/config/environment.ts +67 -1
- package/src/config/index.ts +13 -3
- package/src/config/validation-helpers.ts +207 -23
- package/src/config/validation.ts +344 -129
- package/src/{api/preview.ts → create-worker-preview.ts} +39 -20
- package/src/{api/form_data.ts → create-worker-upload-form.ts} +1 -1
- package/src/dev/dev.tsx +392 -0
- package/src/dev/local.tsx +232 -0
- package/src/dev/remote.tsx +203 -0
- package/src/dev/use-esbuild.ts +104 -0
- package/src/entry.ts +192 -9
- package/src/https-options.ts +122 -0
- package/src/index.tsx +577 -515
- package/src/inspect.ts +9 -1
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv.tsx → kv.ts} +97 -53
- package/src/miniflare-cli/README.md +30 -0
- package/src/miniflare-cli/enum-keys.ts +17 -0
- package/src/miniflare-cli/index.ts +37 -0
- package/src/module-collection.ts +90 -2
- package/src/open-in-browser.ts +14 -2
- package/src/pages.tsx +26 -10
- package/src/proxy.ts +104 -40
- package/src/publish.ts +53 -71
- package/src/reporting.ts +25 -9
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +68 -29
- package/src/user.tsx +163 -85
- package/src/{api/worker.ts → worker.ts} +1 -24
- package/wrangler-dist/cli.js +5933 -3842
- package/wrangler-dist/cli.js.map +3 -3
- package/src/__tests__/helpers/mock-user.ts +0 -27
- package/src/dev.tsx +0 -961
- package/src/guess-worker-format.ts +0 -68
package/src/config/validation.ts
CHANGED
|
@@ -19,11 +19,23 @@ import {
|
|
|
19
19
|
validateOptionalTypedArray,
|
|
20
20
|
validateRequiredProperty,
|
|
21
21
|
validateTypedArray,
|
|
22
|
+
all,
|
|
23
|
+
isMutuallyExclusiveWith,
|
|
24
|
+
inheritableInLegacyEnvironments,
|
|
25
|
+
appendEnvName,
|
|
26
|
+
getBindingNames,
|
|
22
27
|
} from "./validation-helpers";
|
|
23
|
-
import type { Config,
|
|
24
|
-
import type {
|
|
28
|
+
import type { Config, DevConfig, RawConfig, RawDevConfig } from "./config";
|
|
29
|
+
import type {
|
|
30
|
+
RawEnvironment,
|
|
31
|
+
DeprecatedUpload,
|
|
32
|
+
Environment,
|
|
33
|
+
Rule,
|
|
34
|
+
} from "./environment";
|
|
25
35
|
import type { ValidatorFn } from "./validation-helpers";
|
|
26
36
|
|
|
37
|
+
const ENGLISH = new Intl.ListFormat("en");
|
|
38
|
+
|
|
27
39
|
/**
|
|
28
40
|
* Validate the given `rawConfig` object that was loaded from `configPath`.
|
|
29
41
|
*
|
|
@@ -34,7 +46,8 @@ import type { ValidatorFn } from "./validation-helpers";
|
|
|
34
46
|
*/
|
|
35
47
|
export function normalizeAndValidateConfig(
|
|
36
48
|
rawConfig: RawConfig,
|
|
37
|
-
configPath: string | undefined
|
|
49
|
+
configPath: string | undefined,
|
|
50
|
+
args: unknown
|
|
38
51
|
): {
|
|
39
52
|
config: Config;
|
|
40
53
|
diagnostics: Diagnostics;
|
|
@@ -61,10 +74,13 @@ export function normalizeAndValidateConfig(
|
|
|
61
74
|
true
|
|
62
75
|
);
|
|
63
76
|
|
|
64
|
-
|
|
77
|
+
deprecated(
|
|
65
78
|
diagnostics,
|
|
66
79
|
rawConfig,
|
|
67
|
-
|
|
80
|
+
`site.entry-point`,
|
|
81
|
+
`The \`site.entry-point\` config field is no longer used.\nThe entry-point should be specified via the command line or the \`main\` config field.`,
|
|
82
|
+
false,
|
|
83
|
+
true
|
|
68
84
|
);
|
|
69
85
|
|
|
70
86
|
validateOptionalProperty(
|
|
@@ -75,23 +91,79 @@ export function normalizeAndValidateConfig(
|
|
|
75
91
|
"boolean"
|
|
76
92
|
);
|
|
77
93
|
|
|
94
|
+
// TODO: set the default to false to turn on service environments as the default
|
|
95
|
+
const isLegacyEnv =
|
|
96
|
+
(args as { "legacy-env": boolean | undefined })["legacy-env"] ??
|
|
97
|
+
rawConfig.legacy_env ??
|
|
98
|
+
true;
|
|
99
|
+
|
|
100
|
+
const topLevelEnv = normalizeAndValidateEnvironment(
|
|
101
|
+
diagnostics,
|
|
102
|
+
configPath,
|
|
103
|
+
rawConfig
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
//TODO: find a better way to define the type of Args that can be passed to the normalizeAndValidateConfig()
|
|
107
|
+
const envName = (args as { env: string | undefined }).env;
|
|
108
|
+
|
|
109
|
+
let activeEnv = topLevelEnv;
|
|
110
|
+
if (envName !== undefined) {
|
|
111
|
+
const envDiagnostics = new Diagnostics(
|
|
112
|
+
`"env.${envName}" environment configuration`
|
|
113
|
+
);
|
|
114
|
+
const rawEnv = rawConfig.env?.[envName];
|
|
115
|
+
if (rawEnv !== undefined) {
|
|
116
|
+
activeEnv = normalizeAndValidateEnvironment(
|
|
117
|
+
envDiagnostics,
|
|
118
|
+
configPath,
|
|
119
|
+
rawEnv,
|
|
120
|
+
envName,
|
|
121
|
+
topLevelEnv,
|
|
122
|
+
isLegacyEnv,
|
|
123
|
+
rawConfig
|
|
124
|
+
);
|
|
125
|
+
diagnostics.addChild(envDiagnostics);
|
|
126
|
+
} else {
|
|
127
|
+
// An environment was specified, but no configuration for it was found.
|
|
128
|
+
// To cover any legacy environment cases, where the `envName` is used,
|
|
129
|
+
// Let's create a fake active environment with the specified `envName`.
|
|
130
|
+
activeEnv = normalizeAndValidateEnvironment(
|
|
131
|
+
envDiagnostics,
|
|
132
|
+
configPath,
|
|
133
|
+
{},
|
|
134
|
+
envName,
|
|
135
|
+
topLevelEnv,
|
|
136
|
+
isLegacyEnv,
|
|
137
|
+
rawConfig
|
|
138
|
+
);
|
|
139
|
+
const envNames = rawConfig.env
|
|
140
|
+
? `The available configured environment names are: ${JSON.stringify(
|
|
141
|
+
Object.keys(rawConfig.env)
|
|
142
|
+
)}\n`
|
|
143
|
+
: "";
|
|
144
|
+
const message =
|
|
145
|
+
`No environment found in configuration with name "${envName}".\n` +
|
|
146
|
+
`Before using \`--env=${envName}\` there should be an equivalent environment section in the configuration.\n` +
|
|
147
|
+
`${envNames}\n` +
|
|
148
|
+
`Consider adding an environment configuration section to the wrangler.toml file:\n` +
|
|
149
|
+
"```\n[env." +
|
|
150
|
+
envName +
|
|
151
|
+
"]\n```\n";
|
|
152
|
+
|
|
153
|
+
if (envNames.length > 0) {
|
|
154
|
+
diagnostics.errors.push(message);
|
|
155
|
+
} else {
|
|
156
|
+
// Only warn (rather than error) if there are not actually any environments configured in wrangler.toml.
|
|
157
|
+
diagnostics.warnings.push(message);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
78
162
|
// Process the top-level default environment configuration.
|
|
79
163
|
const config: Config = {
|
|
80
164
|
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()`.
|
|
165
|
+
legacy_env: isLegacyEnv,
|
|
166
|
+
...activeEnv,
|
|
95
167
|
dev: normalizeAndValidateDev(diagnostics, rawConfig.dev ?? {}),
|
|
96
168
|
migrations: normalizeAndValidateMigrations(
|
|
97
169
|
diagnostics,
|
|
@@ -110,33 +182,15 @@ export function normalizeAndValidateConfig(
|
|
|
110
182
|
"text_blobs",
|
|
111
183
|
rawConfig.text_blobs
|
|
112
184
|
),
|
|
113
|
-
build,
|
|
114
185
|
};
|
|
115
186
|
|
|
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
|
-
}
|
|
187
|
+
validateBindingsHaveUniqueNames(diagnostics, config);
|
|
134
188
|
|
|
135
189
|
validateAdditionalProperties(
|
|
136
190
|
diagnostics,
|
|
137
191
|
"top-level",
|
|
138
192
|
Object.keys(rawConfig),
|
|
139
|
-
Object.keys(config)
|
|
193
|
+
[...Object.keys(config), "env", "miniflare"]
|
|
140
194
|
);
|
|
141
195
|
|
|
142
196
|
return { config, diagnostics };
|
|
@@ -147,8 +201,9 @@ export function normalizeAndValidateConfig(
|
|
|
147
201
|
*/
|
|
148
202
|
function normalizeAndValidateBuild(
|
|
149
203
|
diagnostics: Diagnostics,
|
|
150
|
-
|
|
151
|
-
rawBuild: Config["build"]
|
|
204
|
+
rawEnv: RawEnvironment,
|
|
205
|
+
rawBuild: Config["build"],
|
|
206
|
+
configPath: string | undefined
|
|
152
207
|
): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
|
|
153
208
|
const { command, cwd, watch_dir, upload, ...rest } = rawBuild;
|
|
154
209
|
const deprecatedUpload: DeprecatedUpload = { ...upload };
|
|
@@ -166,13 +221,13 @@ function normalizeAndValidateBuild(
|
|
|
166
221
|
|
|
167
222
|
deprecated(
|
|
168
223
|
diagnostics,
|
|
169
|
-
|
|
224
|
+
rawEnv,
|
|
170
225
|
"build.upload.format",
|
|
171
226
|
"The format is inferred automatically from the code.",
|
|
172
227
|
true
|
|
173
228
|
);
|
|
174
229
|
|
|
175
|
-
if (
|
|
230
|
+
if (rawEnv.main !== undefined && rawBuild.upload?.main) {
|
|
176
231
|
diagnostics.errors.push(
|
|
177
232
|
`Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.\n` +
|
|
178
233
|
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
@@ -181,7 +236,7 @@ function normalizeAndValidateBuild(
|
|
|
181
236
|
} else {
|
|
182
237
|
deprecated(
|
|
183
238
|
diagnostics,
|
|
184
|
-
|
|
239
|
+
rawEnv,
|
|
185
240
|
"build.upload.main",
|
|
186
241
|
`Delete the \`build.upload.main\` and \`build.upload.dir\` fields.\n` +
|
|
187
242
|
`Then add the top level \`main\` field to your configuration file:\n` +
|
|
@@ -196,24 +251,41 @@ function normalizeAndValidateBuild(
|
|
|
196
251
|
|
|
197
252
|
deprecated(
|
|
198
253
|
diagnostics,
|
|
199
|
-
|
|
254
|
+
rawEnv,
|
|
200
255
|
"build.upload.dir",
|
|
201
256
|
`Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`,
|
|
202
257
|
true
|
|
203
258
|
);
|
|
204
259
|
}
|
|
205
260
|
|
|
206
|
-
return {
|
|
261
|
+
return {
|
|
262
|
+
command,
|
|
263
|
+
watch_dir:
|
|
264
|
+
// - `watch_dir` only matters when `command` is defined, so we apply
|
|
265
|
+
// a default only when `command` is defined
|
|
266
|
+
// - `configPath` will always be defined since `build` can only
|
|
267
|
+
// be configured in `wrangler.toml`, but who knows, that may
|
|
268
|
+
// change in the future, so we do a check anyway
|
|
269
|
+
command
|
|
270
|
+
? configPath
|
|
271
|
+
? path.relative(
|
|
272
|
+
process.cwd(),
|
|
273
|
+
path.join(path.dirname(configPath), watch_dir || "./src")
|
|
274
|
+
)
|
|
275
|
+
: watch_dir || "./src"
|
|
276
|
+
: watch_dir,
|
|
277
|
+
cwd,
|
|
278
|
+
deprecatedUpload,
|
|
279
|
+
};
|
|
207
280
|
}
|
|
208
281
|
|
|
209
282
|
/**
|
|
210
283
|
* Validate the `main` field and return the normalized values.
|
|
211
284
|
*/
|
|
212
285
|
function normalizeAndValidateMainField(
|
|
213
|
-
diagnostics: Diagnostics,
|
|
214
286
|
configPath: string | undefined,
|
|
215
287
|
rawMain: string | undefined,
|
|
216
|
-
deprecatedUpload:
|
|
288
|
+
deprecatedUpload: DeprecatedUpload | undefined
|
|
217
289
|
): string | undefined {
|
|
218
290
|
const configDir = path.dirname(configPath ?? "wrangler.toml");
|
|
219
291
|
if (rawMain !== undefined) {
|
|
@@ -221,13 +293,13 @@ function normalizeAndValidateMainField(
|
|
|
221
293
|
const directory = path.resolve(configDir);
|
|
222
294
|
return path.resolve(directory, rawMain);
|
|
223
295
|
} else {
|
|
224
|
-
|
|
225
|
-
`ERROR: "main" should be a string but got ${JSON.stringify(rawMain)}`
|
|
226
|
-
);
|
|
227
|
-
return;
|
|
296
|
+
return rawMain;
|
|
228
297
|
}
|
|
229
|
-
} else if (deprecatedUpload
|
|
230
|
-
const directory = path.resolve(
|
|
298
|
+
} else if (deprecatedUpload?.main !== undefined) {
|
|
299
|
+
const directory = path.resolve(
|
|
300
|
+
configDir,
|
|
301
|
+
deprecatedUpload?.dir || "./dist"
|
|
302
|
+
);
|
|
231
303
|
return path.resolve(directory, deprecatedUpload.main);
|
|
232
304
|
} else {
|
|
233
305
|
return;
|
|
@@ -239,13 +311,14 @@ function normalizeAndValidateMainField(
|
|
|
239
311
|
*/
|
|
240
312
|
function normalizeAndValidateDev(
|
|
241
313
|
diagnostics: Diagnostics,
|
|
242
|
-
rawDev:
|
|
243
|
-
):
|
|
314
|
+
rawDev: RawDevConfig
|
|
315
|
+
): DevConfig {
|
|
244
316
|
const {
|
|
245
|
-
ip = "
|
|
317
|
+
ip = "localhost",
|
|
246
318
|
port = 8787,
|
|
247
319
|
local_protocol = "http",
|
|
248
320
|
upstream_protocol = "https",
|
|
321
|
+
host,
|
|
249
322
|
...rest
|
|
250
323
|
} = rawDev;
|
|
251
324
|
validateAdditionalProperties(diagnostics, "dev", Object.keys(rest), []);
|
|
@@ -257,16 +330,19 @@ function normalizeAndValidateDev(
|
|
|
257
330
|
"dev",
|
|
258
331
|
"local_protocol",
|
|
259
332
|
local_protocol,
|
|
260
|
-
"string"
|
|
333
|
+
"string",
|
|
334
|
+
["http", "https"]
|
|
261
335
|
);
|
|
262
336
|
validateOptionalProperty(
|
|
263
337
|
diagnostics,
|
|
264
338
|
"dev",
|
|
265
339
|
"upstream_protocol",
|
|
266
340
|
upstream_protocol,
|
|
267
|
-
"string"
|
|
341
|
+
"string",
|
|
342
|
+
["http", "https"]
|
|
268
343
|
);
|
|
269
|
-
|
|
344
|
+
validateOptionalProperty(diagnostics, "dev", "host", host, "string");
|
|
345
|
+
return { ip, port, local_protocol, upstream_protocol, host };
|
|
270
346
|
}
|
|
271
347
|
|
|
272
348
|
/**
|
|
@@ -302,7 +378,7 @@ function normalizeAndValidateMigrations(
|
|
|
302
378
|
if (migration.renamed_classes !== undefined) {
|
|
303
379
|
if (!Array.isArray(migration.renamed_classes)) {
|
|
304
380
|
diagnostics.errors.push(
|
|
305
|
-
`"migrations[${i}].renamed_classes"
|
|
381
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
306
382
|
migration.renamed_classes
|
|
307
383
|
)}.`
|
|
308
384
|
);
|
|
@@ -315,7 +391,7 @@ function normalizeAndValidateMigrations(
|
|
|
315
391
|
)
|
|
316
392
|
) {
|
|
317
393
|
diagnostics.errors.push(
|
|
318
|
-
`"migrations[${i}].renamed_classes"
|
|
394
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
319
395
|
migration.renamed_classes
|
|
320
396
|
)}.`
|
|
321
397
|
);
|
|
@@ -340,25 +416,12 @@ function normalizeAndValidateSite(
|
|
|
340
416
|
rawSite: Config["site"]
|
|
341
417
|
): Config["site"] {
|
|
342
418
|
if (rawSite !== undefined) {
|
|
343
|
-
const {
|
|
344
|
-
bucket,
|
|
345
|
-
"entry-point": entryPoint,
|
|
346
|
-
include = [],
|
|
347
|
-
exclude = [],
|
|
348
|
-
...rest
|
|
349
|
-
} = rawSite;
|
|
419
|
+
const { bucket, include = [], exclude = [], ...rest } = rawSite;
|
|
350
420
|
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), []);
|
|
351
421
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
352
|
-
validateOptionalProperty(
|
|
353
|
-
diagnostics,
|
|
354
|
-
"site",
|
|
355
|
-
"entry_point",
|
|
356
|
-
entryPoint,
|
|
357
|
-
"string"
|
|
358
|
-
);
|
|
359
422
|
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
360
423
|
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
361
|
-
return { bucket,
|
|
424
|
+
return { bucket, include, exclude };
|
|
362
425
|
}
|
|
363
426
|
return undefined;
|
|
364
427
|
}
|
|
@@ -397,26 +460,28 @@ function normalizeAndValidateModulePaths(
|
|
|
397
460
|
*/
|
|
398
461
|
function normalizeAndValidateEnvironment(
|
|
399
462
|
diagnostics: Diagnostics,
|
|
400
|
-
|
|
401
|
-
|
|
463
|
+
configPath: string | undefined,
|
|
464
|
+
topLevelEnv: RawEnvironment
|
|
402
465
|
): Environment;
|
|
403
466
|
/**
|
|
404
467
|
* Validate the named environment configuration and return the normalized values.
|
|
405
468
|
*/
|
|
406
469
|
function normalizeAndValidateEnvironment(
|
|
407
470
|
diagnostics: Diagnostics,
|
|
471
|
+
configPath: string | undefined,
|
|
408
472
|
rawEnv: RawEnvironment,
|
|
409
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
410
473
|
envName: string,
|
|
411
|
-
|
|
474
|
+
topLevelEnv: Environment,
|
|
475
|
+
isLegacyEnv: boolean,
|
|
412
476
|
rawConfig: RawConfig
|
|
413
477
|
): Environment;
|
|
414
478
|
function normalizeAndValidateEnvironment(
|
|
415
479
|
diagnostics: Diagnostics,
|
|
480
|
+
configPath: string | undefined,
|
|
416
481
|
rawEnv: RawEnvironment,
|
|
417
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
418
482
|
envName = "top level",
|
|
419
|
-
|
|
483
|
+
topLevelEnv?: Environment | undefined,
|
|
484
|
+
isLegacyEnv?: boolean,
|
|
420
485
|
rawConfig?: RawConfig | undefined
|
|
421
486
|
): Environment {
|
|
422
487
|
deprecated(
|
|
@@ -457,7 +522,7 @@ function normalizeAndValidateEnvironment(
|
|
|
457
522
|
|
|
458
523
|
const route = inheritable(
|
|
459
524
|
diagnostics,
|
|
460
|
-
|
|
525
|
+
topLevelEnv,
|
|
461
526
|
rawEnv,
|
|
462
527
|
"route",
|
|
463
528
|
isString,
|
|
@@ -465,26 +530,33 @@ function normalizeAndValidateEnvironment(
|
|
|
465
530
|
);
|
|
466
531
|
const routes = inheritable(
|
|
467
532
|
diagnostics,
|
|
468
|
-
|
|
533
|
+
topLevelEnv,
|
|
469
534
|
rawEnv,
|
|
470
535
|
"routes",
|
|
471
|
-
isStringArray,
|
|
536
|
+
all(isStringArray, isMutuallyExclusiveWith(rawEnv, "route")),
|
|
472
537
|
undefined
|
|
473
538
|
);
|
|
474
539
|
const workers_dev = inheritable(
|
|
475
540
|
diagnostics,
|
|
476
|
-
|
|
541
|
+
topLevelEnv,
|
|
477
542
|
rawEnv,
|
|
478
543
|
"workers_dev",
|
|
479
544
|
isBoolean,
|
|
480
|
-
|
|
545
|
+
undefined
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
549
|
+
diagnostics,
|
|
550
|
+
rawEnv,
|
|
551
|
+
rawEnv.build ?? topLevelEnv?.build ?? {},
|
|
552
|
+
configPath
|
|
481
553
|
);
|
|
482
554
|
|
|
483
555
|
const environment: Environment = {
|
|
484
556
|
// Inherited fields
|
|
485
557
|
account_id: inheritable(
|
|
486
558
|
diagnostics,
|
|
487
|
-
|
|
559
|
+
topLevelEnv,
|
|
488
560
|
rawEnv,
|
|
489
561
|
"account_id",
|
|
490
562
|
isString,
|
|
@@ -492,7 +564,7 @@ function normalizeAndValidateEnvironment(
|
|
|
492
564
|
),
|
|
493
565
|
compatibility_date: inheritable(
|
|
494
566
|
diagnostics,
|
|
495
|
-
|
|
567
|
+
topLevelEnv,
|
|
496
568
|
rawEnv,
|
|
497
569
|
"compatibility_date",
|
|
498
570
|
isString,
|
|
@@ -500,7 +572,7 @@ function normalizeAndValidateEnvironment(
|
|
|
500
572
|
),
|
|
501
573
|
compatibility_flags: inheritable(
|
|
502
574
|
diagnostics,
|
|
503
|
-
|
|
575
|
+
topLevelEnv,
|
|
504
576
|
rawEnv,
|
|
505
577
|
"compatibility_flags",
|
|
506
578
|
isStringArray,
|
|
@@ -508,7 +580,7 @@ function normalizeAndValidateEnvironment(
|
|
|
508
580
|
),
|
|
509
581
|
jsx_factory: inheritable(
|
|
510
582
|
diagnostics,
|
|
511
|
-
|
|
583
|
+
topLevelEnv,
|
|
512
584
|
rawEnv,
|
|
513
585
|
"jsx_factory",
|
|
514
586
|
isString,
|
|
@@ -516,25 +588,52 @@ function normalizeAndValidateEnvironment(
|
|
|
516
588
|
),
|
|
517
589
|
jsx_fragment: inheritable(
|
|
518
590
|
diagnostics,
|
|
519
|
-
|
|
591
|
+
topLevelEnv,
|
|
520
592
|
rawEnv,
|
|
521
593
|
"jsx_fragment",
|
|
522
594
|
isString,
|
|
523
595
|
"React.Fragment"
|
|
524
596
|
),
|
|
597
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
598
|
+
diagnostics,
|
|
599
|
+
topLevelEnv,
|
|
600
|
+
rawEnv,
|
|
601
|
+
configPath
|
|
602
|
+
),
|
|
525
603
|
rules: validateAndNormalizeRules(
|
|
526
604
|
diagnostics,
|
|
527
|
-
|
|
605
|
+
topLevelEnv,
|
|
528
606
|
rawEnv,
|
|
529
|
-
|
|
607
|
+
deprecatedUpload?.rules,
|
|
530
608
|
envName
|
|
531
609
|
),
|
|
532
|
-
name:
|
|
610
|
+
name: inheritableInLegacyEnvironments(
|
|
611
|
+
diagnostics,
|
|
612
|
+
isLegacyEnv,
|
|
613
|
+
topLevelEnv,
|
|
614
|
+
rawEnv,
|
|
615
|
+
"name",
|
|
616
|
+
isString,
|
|
617
|
+
appendEnvName(envName),
|
|
618
|
+
undefined
|
|
619
|
+
),
|
|
620
|
+
main: normalizeAndValidateMainField(
|
|
621
|
+
configPath,
|
|
622
|
+
inheritable(
|
|
623
|
+
diagnostics,
|
|
624
|
+
topLevelEnv,
|
|
625
|
+
rawEnv,
|
|
626
|
+
"main",
|
|
627
|
+
isString,
|
|
628
|
+
undefined
|
|
629
|
+
),
|
|
630
|
+
deprecatedUpload
|
|
631
|
+
),
|
|
533
632
|
route,
|
|
534
633
|
routes,
|
|
535
634
|
triggers: inheritable(
|
|
536
635
|
diagnostics,
|
|
537
|
-
|
|
636
|
+
topLevelEnv,
|
|
538
637
|
rawEnv,
|
|
539
638
|
"triggers",
|
|
540
639
|
isObjectWith("crons"),
|
|
@@ -542,17 +641,18 @@ function normalizeAndValidateEnvironment(
|
|
|
542
641
|
),
|
|
543
642
|
usage_model: inheritable(
|
|
544
643
|
diagnostics,
|
|
545
|
-
|
|
644
|
+
topLevelEnv,
|
|
546
645
|
rawEnv,
|
|
547
646
|
"usage_model",
|
|
548
647
|
isOneOf("bundled", "unbound"),
|
|
549
648
|
undefined
|
|
550
649
|
),
|
|
650
|
+
build,
|
|
551
651
|
workers_dev,
|
|
552
652
|
// Not inherited fields
|
|
553
653
|
vars: notInheritable(
|
|
554
654
|
diagnostics,
|
|
555
|
-
|
|
655
|
+
topLevelEnv,
|
|
556
656
|
rawConfig,
|
|
557
657
|
rawEnv,
|
|
558
658
|
envName,
|
|
@@ -562,7 +662,7 @@ function normalizeAndValidateEnvironment(
|
|
|
562
662
|
),
|
|
563
663
|
durable_objects: notInheritable(
|
|
564
664
|
diagnostics,
|
|
565
|
-
|
|
665
|
+
topLevelEnv,
|
|
566
666
|
rawConfig,
|
|
567
667
|
rawEnv,
|
|
568
668
|
envName,
|
|
@@ -574,7 +674,7 @@ function normalizeAndValidateEnvironment(
|
|
|
574
674
|
),
|
|
575
675
|
kv_namespaces: notInheritable(
|
|
576
676
|
diagnostics,
|
|
577
|
-
|
|
677
|
+
topLevelEnv,
|
|
578
678
|
rawConfig,
|
|
579
679
|
rawEnv,
|
|
580
680
|
envName,
|
|
@@ -584,7 +684,7 @@ function normalizeAndValidateEnvironment(
|
|
|
584
684
|
),
|
|
585
685
|
r2_buckets: notInheritable(
|
|
586
686
|
diagnostics,
|
|
587
|
-
|
|
687
|
+
topLevelEnv,
|
|
588
688
|
rawConfig,
|
|
589
689
|
rawEnv,
|
|
590
690
|
envName,
|
|
@@ -594,7 +694,7 @@ function normalizeAndValidateEnvironment(
|
|
|
594
694
|
),
|
|
595
695
|
unsafe: notInheritable(
|
|
596
696
|
diagnostics,
|
|
597
|
-
|
|
697
|
+
topLevelEnv,
|
|
598
698
|
rawConfig,
|
|
599
699
|
rawEnv,
|
|
600
700
|
envName,
|
|
@@ -610,18 +710,41 @@ function normalizeAndValidateEnvironment(
|
|
|
610
710
|
return environment;
|
|
611
711
|
}
|
|
612
712
|
|
|
713
|
+
function validateAndNormalizeTsconfig(
|
|
714
|
+
diagnostics: Diagnostics,
|
|
715
|
+
topLevelEnv: Environment | undefined,
|
|
716
|
+
rawEnv: RawEnvironment,
|
|
717
|
+
configPath: string | undefined
|
|
718
|
+
) {
|
|
719
|
+
const tsconfig = inheritable(
|
|
720
|
+
diagnostics,
|
|
721
|
+
topLevelEnv,
|
|
722
|
+
rawEnv,
|
|
723
|
+
"tsconfig",
|
|
724
|
+
isString,
|
|
725
|
+
undefined
|
|
726
|
+
);
|
|
727
|
+
|
|
728
|
+
return configPath && tsconfig
|
|
729
|
+
? path.relative(
|
|
730
|
+
process.cwd(),
|
|
731
|
+
path.join(path.dirname(configPath), tsconfig)
|
|
732
|
+
)
|
|
733
|
+
: tsconfig;
|
|
734
|
+
}
|
|
735
|
+
|
|
613
736
|
const validateAndNormalizeRules = (
|
|
614
737
|
diagnostics: Diagnostics,
|
|
615
|
-
|
|
738
|
+
topLevelEnv: Environment | undefined,
|
|
616
739
|
rawEnv: RawEnvironment,
|
|
617
740
|
deprecatedRules: Rule[] | undefined,
|
|
618
741
|
envName: string
|
|
619
742
|
): Rule[] => {
|
|
620
|
-
if (
|
|
743
|
+
if (topLevelEnv === undefined) {
|
|
621
744
|
// Only create errors/warnings for the top-level environment
|
|
622
745
|
if (rawEnv.rules && deprecatedRules) {
|
|
623
746
|
diagnostics.errors.push(
|
|
624
|
-
`
|
|
747
|
+
`You cannot configure both [rules] and [build.upload.rules] in your wrangler.toml. Delete the \`build.upload\` section.`
|
|
625
748
|
);
|
|
626
749
|
} else if (deprecatedRules) {
|
|
627
750
|
diagnostics.warnings.push(
|
|
@@ -635,7 +758,7 @@ const validateAndNormalizeRules = (
|
|
|
635
758
|
|
|
636
759
|
return inheritable(
|
|
637
760
|
diagnostics,
|
|
638
|
-
|
|
761
|
+
topLevelEnv,
|
|
639
762
|
rawEnv,
|
|
640
763
|
"rules",
|
|
641
764
|
validateRules(envName),
|
|
@@ -671,7 +794,9 @@ const validateRules =
|
|
|
671
794
|
|
|
672
795
|
const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
673
796
|
if (typeof value !== "object" || value === null) {
|
|
674
|
-
diagnostics.errors.push(
|
|
797
|
+
diagnostics.errors.push(
|
|
798
|
+
`"${field}" should be an object but got ${JSON.stringify(value)}.`
|
|
799
|
+
);
|
|
675
800
|
return false;
|
|
676
801
|
}
|
|
677
802
|
// Rules must have a type string and glob string array, and optionally a fallthrough boolean.
|
|
@@ -688,7 +813,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
688
813
|
])
|
|
689
814
|
) {
|
|
690
815
|
diagnostics.errors.push(
|
|
691
|
-
`
|
|
816
|
+
`bindings should have a string "type" field, which contains one of "ESModule", "CommonJS", "CompiledWasm", "Text", or "Data".`
|
|
692
817
|
);
|
|
693
818
|
isValid = false;
|
|
694
819
|
}
|
|
@@ -699,7 +824,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
699
824
|
|
|
700
825
|
if (!isOptionalProperty(rule, "fallthrough", "boolean")) {
|
|
701
826
|
diagnostics.errors.push(
|
|
702
|
-
`
|
|
827
|
+
`binding should, optionally, have a boolean "fallthrough" field.`
|
|
703
828
|
);
|
|
704
829
|
isValid = false;
|
|
705
830
|
}
|
|
@@ -805,42 +930,34 @@ const validateBindingsProperty =
|
|
|
805
930
|
return isValid;
|
|
806
931
|
};
|
|
807
932
|
|
|
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
933
|
/**
|
|
817
934
|
* Check that the given field is a valid "durable_object" binding object.
|
|
818
935
|
*/
|
|
819
936
|
const validateDurableObjectBinding: ValidatorFn = (
|
|
820
937
|
diagnostics,
|
|
821
|
-
|
|
938
|
+
field,
|
|
822
939
|
value
|
|
823
940
|
) => {
|
|
824
941
|
if (typeof value !== "object" || value === null) {
|
|
825
|
-
diagnostics.errors.push(
|
|
942
|
+
diagnostics.errors.push(
|
|
943
|
+
`Expected "${field}" to be an object but got ${JSON.stringify(value)}`
|
|
944
|
+
);
|
|
826
945
|
return false;
|
|
827
946
|
}
|
|
828
947
|
|
|
829
948
|
// Durable Object bindings must have a name and class_name, and optionally a script_name.
|
|
830
949
|
let isValid = true;
|
|
831
950
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
832
|
-
diagnostics.errors.push(
|
|
833
|
-
`ERROR: bindings should have a string "name" field.`
|
|
834
|
-
);
|
|
951
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
835
952
|
isValid = false;
|
|
836
953
|
}
|
|
837
954
|
if (!isRequiredProperty(value, "class_name", "string")) {
|
|
838
|
-
diagnostics.errors.push(`
|
|
955
|
+
diagnostics.errors.push(`binding should have a string "class_name" field.`);
|
|
839
956
|
isValid = false;
|
|
840
957
|
}
|
|
841
958
|
if (!isOptionalProperty(value, "script_name", "string")) {
|
|
842
959
|
diagnostics.errors.push(
|
|
843
|
-
`
|
|
960
|
+
`binding should, optionally, have a string "script_name" field.`
|
|
844
961
|
);
|
|
845
962
|
isValid = false;
|
|
846
963
|
}
|
|
@@ -853,16 +970,18 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
853
970
|
*
|
|
854
971
|
* TODO: further validation of known unsafe bindings.
|
|
855
972
|
*/
|
|
856
|
-
const validateUnsafeBinding: ValidatorFn = (diagnostics,
|
|
973
|
+
const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
857
974
|
if (typeof value !== "object" || value === null) {
|
|
858
|
-
diagnostics.errors.push(
|
|
975
|
+
diagnostics.errors.push(
|
|
976
|
+
`Expected ${field} to be an object but got ${JSON.stringify(value)}.`
|
|
977
|
+
);
|
|
859
978
|
return false;
|
|
860
979
|
}
|
|
861
980
|
|
|
862
981
|
let isValid = true;
|
|
863
982
|
// Unsafe bindings must have a name and type.
|
|
864
983
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
865
|
-
diagnostics.errors.push(`
|
|
984
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
866
985
|
isValid = false;
|
|
867
986
|
}
|
|
868
987
|
if (isRequiredProperty(value, "type", "string")) {
|
|
@@ -881,7 +1000,7 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, _field, value) => {
|
|
|
881
1000
|
);
|
|
882
1001
|
}
|
|
883
1002
|
} else {
|
|
884
|
-
diagnostics.errors.push(`
|
|
1003
|
+
diagnostics.errors.push(`binding should have a string "type" field.`);
|
|
885
1004
|
isValid = false;
|
|
886
1005
|
}
|
|
887
1006
|
return isValid;
|
|
@@ -1015,3 +1134,99 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1015
1134
|
}
|
|
1016
1135
|
return isValid;
|
|
1017
1136
|
};
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Check that bindings whose names might conflict, don't.
|
|
1140
|
+
*
|
|
1141
|
+
* We don't want to have, for example, a KV namespace named "DATA"
|
|
1142
|
+
* and a Durable Object also named "DATA". Then it would be ambiguous
|
|
1143
|
+
* what exactly would live at `env.DATA` (or in the case of service workers,
|
|
1144
|
+
* the `DATA` global).
|
|
1145
|
+
*/
|
|
1146
|
+
const validateBindingsHaveUniqueNames = (
|
|
1147
|
+
diagnostics: Diagnostics,
|
|
1148
|
+
{
|
|
1149
|
+
durable_objects,
|
|
1150
|
+
kv_namespaces,
|
|
1151
|
+
r2_buckets,
|
|
1152
|
+
text_blobs,
|
|
1153
|
+
unsafe,
|
|
1154
|
+
vars,
|
|
1155
|
+
wasm_modules,
|
|
1156
|
+
}: Partial<Config>
|
|
1157
|
+
): boolean => {
|
|
1158
|
+
let hasDuplicates = false;
|
|
1159
|
+
|
|
1160
|
+
const bindingsGroupedByType = {
|
|
1161
|
+
"Durable Object": getBindingNames(durable_objects),
|
|
1162
|
+
"KV Namespace": getBindingNames(kv_namespaces),
|
|
1163
|
+
"R2 Bucket": getBindingNames(r2_buckets),
|
|
1164
|
+
"Text Blob": getBindingNames(text_blobs),
|
|
1165
|
+
Unsafe: getBindingNames(unsafe),
|
|
1166
|
+
"Environment Variable": getBindingNames(vars),
|
|
1167
|
+
"WASM Module": getBindingNames(wasm_modules),
|
|
1168
|
+
} as Record<string, string[]>;
|
|
1169
|
+
|
|
1170
|
+
const bindingsGroupedByName: Record<string, string[]> = {};
|
|
1171
|
+
|
|
1172
|
+
for (const bindingType in bindingsGroupedByType) {
|
|
1173
|
+
const bindingNames = bindingsGroupedByType[bindingType];
|
|
1174
|
+
|
|
1175
|
+
for (const bindingName of bindingNames) {
|
|
1176
|
+
if (!(bindingName in bindingsGroupedByName)) {
|
|
1177
|
+
bindingsGroupedByName[bindingName] = [];
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
bindingsGroupedByName[bindingName].push(bindingType);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
for (const bindingName in bindingsGroupedByName) {
|
|
1185
|
+
const bindingTypes = bindingsGroupedByName[bindingName];
|
|
1186
|
+
if (bindingTypes.length < 2) {
|
|
1187
|
+
// there's only one (or zero) binding(s) with this name, which is fine, actually
|
|
1188
|
+
continue;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
hasDuplicates = true;
|
|
1192
|
+
|
|
1193
|
+
// there's two types of duplicates we want to look for:
|
|
1194
|
+
// - bindings with the same name of the same type (e.g. two Durable Objects both named "OBJ")
|
|
1195
|
+
// - bindings with the same name of different types (a KV namespace and DO both named "DATA")
|
|
1196
|
+
|
|
1197
|
+
const sameType = bindingTypes
|
|
1198
|
+
// filter once to find duplicate binding types
|
|
1199
|
+
.filter((type, i) => bindingTypes.indexOf(type) !== i)
|
|
1200
|
+
// filter twice to only get _unique_ duplicate binding types
|
|
1201
|
+
.filter(
|
|
1202
|
+
(type, i, duplicateBindingTypes) =>
|
|
1203
|
+
duplicateBindingTypes.indexOf(type) === i
|
|
1204
|
+
);
|
|
1205
|
+
|
|
1206
|
+
const differentTypes = bindingTypes.filter(
|
|
1207
|
+
(type, i) => bindingTypes.indexOf(type) === i
|
|
1208
|
+
);
|
|
1209
|
+
|
|
1210
|
+
if (differentTypes.length > 1) {
|
|
1211
|
+
// we have multiple different types using the same name
|
|
1212
|
+
diagnostics.errors.push(
|
|
1213
|
+
`${bindingName} assigned to ${ENGLISH.format(differentTypes)} bindings.`
|
|
1214
|
+
);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
sameType.forEach((bindingType) => {
|
|
1218
|
+
diagnostics.errors.push(
|
|
1219
|
+
`${bindingName} assigned to multiple ${bindingType} bindings.`
|
|
1220
|
+
);
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
if (hasDuplicates) {
|
|
1225
|
+
const problem =
|
|
1226
|
+
"Bindings must have unique names, so that they can all be referenced in the worker.";
|
|
1227
|
+
const resolution = "Please change your bindings to have unique names.";
|
|
1228
|
+
diagnostics.errors.push(`${problem}\n${resolution}`);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
return !hasDuplicates;
|
|
1232
|
+
};
|