wrangler 0.0.0-e95bea2 → 0.0.0-e95e5a0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4886 -0
- package/package.json +33 -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 +1179 -271
- package/src/__tests__/dev.test.tsx +382 -25
- package/src/__tests__/guess-worker-format.test.ts +28 -1
- package/src/__tests__/helpers/mock-account-id.ts +4 -0
- package/src/__tests__/helpers/mock-cfetch.ts +5 -1
- package/src/__tests__/helpers/mock-console.ts +20 -3
- package/src/__tests__/helpers/mock-dialogs.ts +26 -1
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/helpers/mock-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 +5 -2
- package/src/__tests__/index.test.ts +27 -769
- package/src/__tests__/init.test.ts +1516 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +172 -126
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +311 -26
- package/src/__tests__/publish.test.ts +2946 -524
- package/src/__tests__/r2.test.ts +26 -10
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +26 -7
- package/src/bundle.ts +30 -3
- package/src/cfetch/internal.ts +9 -7
- package/src/cli.ts +5 -11
- package/src/config/README.md +7 -7
- package/src/config/config.ts +33 -78
- package/src/config/environment.ts +93 -4
- package/src/config/index.ts +15 -4
- package/src/config/validation-helpers.ts +202 -15
- package/src/config/validation.ts +530 -133
- package/src/config-cache.ts +45 -0
- package/src/create-worker-preview.ts +22 -13
- package/src/create-worker-upload-form.ts +32 -9
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +136 -75
- package/src/dev/local.tsx +196 -125
- package/src/dev/remote.tsx +25 -13
- package/src/dev/use-esbuild.ts +23 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +119 -11
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +739 -400
- package/src/inspect.ts +17 -11
- package/src/intl-polyfill.d.ts +139 -0
- package/src/{kv/index.tsx → kv.ts} +8 -28
- 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 +63 -58
- package/src/open-in-browser.ts +5 -4
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +883 -62
- package/src/parse.ts +1 -1
- package/src/proxy.ts +32 -21
- package/src/publish.ts +276 -161
- 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 +231 -103
- package/src/whoami.tsx +2 -1
- package/src/worker.ts +15 -6
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +22087 -49340
- package/src/__tests__/dev2.test.tsx +0 -152
- 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/reporting.ts +0 -131
- package/wrangler-dist/cli.js.map +0 -7
package/src/config/validation.ts
CHANGED
|
@@ -19,17 +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";
|
|
29
|
+
import type { Config, DevConfig, RawConfig, RawDevConfig } from "./config";
|
|
23
30
|
import type {
|
|
24
|
-
|
|
31
|
+
RawEnvironment,
|
|
25
32
|
DeprecatedUpload,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from "./config";
|
|
30
|
-
import type { RawEnvironment, Environment, Rule } from "./environment";
|
|
33
|
+
Environment,
|
|
34
|
+
Rule,
|
|
35
|
+
} from "./environment";
|
|
31
36
|
import type { ValidatorFn } from "./validation-helpers";
|
|
32
37
|
|
|
38
|
+
const ENGLISH = new Intl.ListFormat("en");
|
|
39
|
+
|
|
33
40
|
/**
|
|
34
41
|
* Validate the given `rawConfig` object that was loaded from `configPath`.
|
|
35
42
|
*
|
|
@@ -40,7 +47,8 @@ import type { ValidatorFn } from "./validation-helpers";
|
|
|
40
47
|
*/
|
|
41
48
|
export function normalizeAndValidateConfig(
|
|
42
49
|
rawConfig: RawConfig,
|
|
43
|
-
configPath: string | undefined
|
|
50
|
+
configPath: string | undefined,
|
|
51
|
+
args: unknown
|
|
44
52
|
): {
|
|
45
53
|
config: Config;
|
|
46
54
|
diagnostics: Diagnostics;
|
|
@@ -54,65 +62,145 @@ export function normalizeAndValidateConfig(
|
|
|
54
62
|
deprecated(
|
|
55
63
|
diagnostics,
|
|
56
64
|
rawConfig,
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
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"
|
|
60
69
|
);
|
|
61
70
|
|
|
62
71
|
deprecated(
|
|
63
72
|
diagnostics,
|
|
64
73
|
rawConfig,
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
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"
|
|
68
78
|
);
|
|
69
79
|
|
|
70
80
|
deprecated(
|
|
71
81
|
diagnostics,
|
|
72
82
|
rawConfig,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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"
|
|
77
87
|
);
|
|
78
88
|
|
|
79
|
-
|
|
89
|
+
validateOptionalProperty(
|
|
80
90
|
diagnostics,
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
"",
|
|
92
|
+
"legacy_env",
|
|
93
|
+
rawConfig.legacy_env,
|
|
94
|
+
"boolean"
|
|
83
95
|
);
|
|
84
96
|
|
|
85
97
|
validateOptionalProperty(
|
|
86
98
|
diagnostics,
|
|
87
99
|
"",
|
|
88
|
-
"
|
|
89
|
-
rawConfig.
|
|
100
|
+
"minify",
|
|
101
|
+
rawConfig.minify,
|
|
90
102
|
"boolean"
|
|
91
103
|
);
|
|
92
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
|
+
|
|
93
188
|
// Process the top-level default environment configuration.
|
|
94
189
|
const config: Config = {
|
|
95
190
|
configPath,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
configPath,
|
|
99
|
-
rawConfig.main,
|
|
100
|
-
deprecatedUpload
|
|
101
|
-
),
|
|
102
|
-
// TODO: set the default to false to turn on service environments as the default
|
|
103
|
-
legacy_env: rawConfig.legacy_env ?? true,
|
|
104
|
-
...normalizeAndValidateEnvironment(
|
|
105
|
-
diagnostics,
|
|
106
|
-
rawConfig,
|
|
107
|
-
deprecatedUpload.rules
|
|
108
|
-
),
|
|
109
|
-
env: {}, // Will be filled below by `normalizeAndValidateEnvironment()`.
|
|
191
|
+
legacy_env: isLegacyEnv,
|
|
192
|
+
...activeEnv,
|
|
110
193
|
dev: normalizeAndValidateDev(diagnostics, rawConfig.dev ?? {}),
|
|
111
194
|
migrations: normalizeAndValidateMigrations(
|
|
112
195
|
diagnostics,
|
|
113
196
|
rawConfig.migrations ?? []
|
|
114
197
|
),
|
|
115
|
-
site: normalizeAndValidateSite(
|
|
198
|
+
site: normalizeAndValidateSite(
|
|
199
|
+
diagnostics,
|
|
200
|
+
configPath,
|
|
201
|
+
rawConfig,
|
|
202
|
+
activeEnv.main
|
|
203
|
+
),
|
|
116
204
|
wasm_modules: normalizeAndValidateModulePaths(
|
|
117
205
|
diagnostics,
|
|
118
206
|
configPath,
|
|
@@ -125,33 +213,21 @@ export function normalizeAndValidateConfig(
|
|
|
125
213
|
"text_blobs",
|
|
126
214
|
rawConfig.text_blobs
|
|
127
215
|
),
|
|
128
|
-
|
|
216
|
+
data_blobs: normalizeAndValidateModulePaths(
|
|
217
|
+
diagnostics,
|
|
218
|
+
configPath,
|
|
219
|
+
"data_blobs",
|
|
220
|
+
rawConfig.data_blobs
|
|
221
|
+
),
|
|
129
222
|
};
|
|
130
223
|
|
|
131
|
-
|
|
132
|
-
if (rawConfig.env !== undefined) {
|
|
133
|
-
for (const envName of Object.keys(rawConfig.env)) {
|
|
134
|
-
const envDiagnostics = new Diagnostics(
|
|
135
|
-
`"env.${envName}" environment configuration`
|
|
136
|
-
);
|
|
137
|
-
const environment = normalizeAndValidateEnvironment(
|
|
138
|
-
envDiagnostics,
|
|
139
|
-
rawConfig.env[envName] as RawEnvironment,
|
|
140
|
-
deprecatedUpload.rules,
|
|
141
|
-
envName,
|
|
142
|
-
config,
|
|
143
|
-
rawConfig
|
|
144
|
-
);
|
|
145
|
-
config.env[envName] = environment;
|
|
146
|
-
diagnostics.addChild(envDiagnostics);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
224
|
+
validateBindingsHaveUniqueNames(diagnostics, config);
|
|
149
225
|
|
|
150
226
|
validateAdditionalProperties(
|
|
151
227
|
diagnostics,
|
|
152
228
|
"top-level",
|
|
153
229
|
Object.keys(rawConfig),
|
|
154
|
-
Object.keys(config)
|
|
230
|
+
[...Object.keys(config), "env"]
|
|
155
231
|
);
|
|
156
232
|
|
|
157
233
|
return { config, diagnostics };
|
|
@@ -162,8 +238,9 @@ export function normalizeAndValidateConfig(
|
|
|
162
238
|
*/
|
|
163
239
|
function normalizeAndValidateBuild(
|
|
164
240
|
diagnostics: Diagnostics,
|
|
165
|
-
|
|
166
|
-
rawBuild: Config["build"]
|
|
241
|
+
rawEnv: RawEnvironment,
|
|
242
|
+
rawBuild: Config["build"],
|
|
243
|
+
configPath: string | undefined
|
|
167
244
|
): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
|
|
168
245
|
const { command, cwd, watch_dir, upload, ...rest } = rawBuild;
|
|
169
246
|
const deprecatedUpload: DeprecatedUpload = { ...upload };
|
|
@@ -181,13 +258,13 @@ function normalizeAndValidateBuild(
|
|
|
181
258
|
|
|
182
259
|
deprecated(
|
|
183
260
|
diagnostics,
|
|
184
|
-
|
|
261
|
+
rawEnv,
|
|
185
262
|
"build.upload.format",
|
|
186
263
|
"The format is inferred automatically from the code.",
|
|
187
264
|
true
|
|
188
265
|
);
|
|
189
266
|
|
|
190
|
-
if (
|
|
267
|
+
if (rawEnv.main !== undefined && rawBuild.upload?.main) {
|
|
191
268
|
diagnostics.errors.push(
|
|
192
269
|
`Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.\n` +
|
|
193
270
|
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
@@ -196,7 +273,7 @@ function normalizeAndValidateBuild(
|
|
|
196
273
|
} else {
|
|
197
274
|
deprecated(
|
|
198
275
|
diagnostics,
|
|
199
|
-
|
|
276
|
+
rawEnv,
|
|
200
277
|
"build.upload.main",
|
|
201
278
|
`Delete the \`build.upload.main\` and \`build.upload.dir\` fields.\n` +
|
|
202
279
|
`Then add the top level \`main\` field to your configuration file:\n` +
|
|
@@ -211,24 +288,41 @@ function normalizeAndValidateBuild(
|
|
|
211
288
|
|
|
212
289
|
deprecated(
|
|
213
290
|
diagnostics,
|
|
214
|
-
|
|
291
|
+
rawEnv,
|
|
215
292
|
"build.upload.dir",
|
|
216
293
|
`Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`,
|
|
217
294
|
true
|
|
218
295
|
);
|
|
219
296
|
}
|
|
220
297
|
|
|
221
|
-
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
|
+
};
|
|
222
317
|
}
|
|
223
318
|
|
|
224
319
|
/**
|
|
225
320
|
* Validate the `main` field and return the normalized values.
|
|
226
321
|
*/
|
|
227
322
|
function normalizeAndValidateMainField(
|
|
228
|
-
diagnostics: Diagnostics,
|
|
229
323
|
configPath: string | undefined,
|
|
230
324
|
rawMain: string | undefined,
|
|
231
|
-
deprecatedUpload:
|
|
325
|
+
deprecatedUpload: DeprecatedUpload | undefined
|
|
232
326
|
): string | undefined {
|
|
233
327
|
const configDir = path.dirname(configPath ?? "wrangler.toml");
|
|
234
328
|
if (rawMain !== undefined) {
|
|
@@ -236,13 +330,13 @@ function normalizeAndValidateMainField(
|
|
|
236
330
|
const directory = path.resolve(configDir);
|
|
237
331
|
return path.resolve(directory, rawMain);
|
|
238
332
|
} else {
|
|
239
|
-
|
|
240
|
-
`Expected "main" to be a string but got ${JSON.stringify(rawMain)}`
|
|
241
|
-
);
|
|
242
|
-
return;
|
|
333
|
+
return rawMain;
|
|
243
334
|
}
|
|
244
|
-
} else if (deprecatedUpload
|
|
245
|
-
const directory = path.resolve(
|
|
335
|
+
} else if (deprecatedUpload?.main !== undefined) {
|
|
336
|
+
const directory = path.resolve(
|
|
337
|
+
configDir,
|
|
338
|
+
deprecatedUpload?.dir || "./dist"
|
|
339
|
+
);
|
|
246
340
|
return path.resolve(directory, deprecatedUpload.main);
|
|
247
341
|
} else {
|
|
248
342
|
return;
|
|
@@ -257,7 +351,7 @@ function normalizeAndValidateDev(
|
|
|
257
351
|
rawDev: RawDevConfig
|
|
258
352
|
): DevConfig {
|
|
259
353
|
const {
|
|
260
|
-
ip = "
|
|
354
|
+
ip = "localhost",
|
|
261
355
|
port = 8787,
|
|
262
356
|
local_protocol = "http",
|
|
263
357
|
upstream_protocol = "https",
|
|
@@ -356,26 +450,91 @@ function normalizeAndValidateMigrations(
|
|
|
356
450
|
*/
|
|
357
451
|
function normalizeAndValidateSite(
|
|
358
452
|
diagnostics: Diagnostics,
|
|
359
|
-
|
|
453
|
+
configPath: string | undefined,
|
|
454
|
+
rawConfig: RawConfig,
|
|
455
|
+
mainEntryPoint: string | undefined
|
|
360
456
|
): Config["site"] {
|
|
361
|
-
if (
|
|
362
|
-
const { bucket, include = [], exclude = [], ...rest } =
|
|
363
|
-
|
|
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
|
+
]);
|
|
364
463
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
365
464
|
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
366
465
|
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
367
|
-
|
|
466
|
+
validateOptionalProperty(
|
|
467
|
+
diagnostics,
|
|
468
|
+
"site",
|
|
469
|
+
"entry-point",
|
|
470
|
+
rawConfig.site["entry-point"],
|
|
471
|
+
"string"
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
deprecated(
|
|
475
|
+
diagnostics,
|
|
476
|
+
rawConfig,
|
|
477
|
+
`site.entry-point`,
|
|
478
|
+
`Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:\n` +
|
|
479
|
+
`\`\`\`\n` +
|
|
480
|
+
`main = "${path.join(
|
|
481
|
+
String(rawConfig.site["entry-point"]) || "workers-site",
|
|
482
|
+
path.extname(String(rawConfig.site["entry-point"]) || "workers-site")
|
|
483
|
+
? ""
|
|
484
|
+
: "index.js"
|
|
485
|
+
)}"\n` +
|
|
486
|
+
`\`\`\``,
|
|
487
|
+
false,
|
|
488
|
+
undefined,
|
|
489
|
+
"warning"
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
let siteEntryPoint = rawConfig.site["entry-point"];
|
|
493
|
+
|
|
494
|
+
if (!mainEntryPoint && !siteEntryPoint) {
|
|
495
|
+
// this means that we're defaulting to "workers-site"
|
|
496
|
+
// so let's add the deprecation warning
|
|
497
|
+
diagnostics.warnings.push(
|
|
498
|
+
`Because you've defined a [site] configuration, we're defaulting to "workers-site" for the deprecated \`site.entry-point\`field.\n` +
|
|
499
|
+
`Add the top level \`main\` field to your configuration file:\n` +
|
|
500
|
+
`\`\`\`\n` +
|
|
501
|
+
`main = "workers-site/index.js"\n` +
|
|
502
|
+
`\`\`\``
|
|
503
|
+
);
|
|
504
|
+
siteEntryPoint = "workers-site";
|
|
505
|
+
} else if (mainEntryPoint && siteEntryPoint) {
|
|
506
|
+
diagnostics.errors.push(
|
|
507
|
+
`Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.\n` +
|
|
508
|
+
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
509
|
+
`Delete the deprecated \`site.entry-point\` field from your config.`
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (configPath && siteEntryPoint) {
|
|
514
|
+
// rewrite the path to be relative to the working directory
|
|
515
|
+
siteEntryPoint = path.relative(
|
|
516
|
+
process.cwd(),
|
|
517
|
+
path.join(path.dirname(configPath), siteEntryPoint)
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
bucket,
|
|
523
|
+
"entry-point": siteEntryPoint,
|
|
524
|
+
include,
|
|
525
|
+
exclude,
|
|
526
|
+
};
|
|
368
527
|
}
|
|
369
528
|
return undefined;
|
|
370
529
|
}
|
|
371
530
|
|
|
372
531
|
/**
|
|
373
|
-
* 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.
|
|
374
533
|
*/
|
|
375
534
|
function normalizeAndValidateModulePaths(
|
|
376
535
|
diagnostics: Diagnostics,
|
|
377
536
|
configPath: string | undefined,
|
|
378
|
-
field: "wasm_modules" | "text_blobs",
|
|
537
|
+
field: "wasm_modules" | "text_blobs" | "data_blobs",
|
|
379
538
|
rawMapping: Record<string, string> | undefined
|
|
380
539
|
): Record<string, string> | undefined {
|
|
381
540
|
if (rawMapping === undefined) {
|
|
@@ -398,31 +557,129 @@ function normalizeAndValidateModulePaths(
|
|
|
398
557
|
return mapping;
|
|
399
558
|
}
|
|
400
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
|
+
|
|
401
656
|
/**
|
|
402
657
|
* Validate top-level environment configuration and return the normalized values.
|
|
403
658
|
*/
|
|
404
659
|
function normalizeAndValidateEnvironment(
|
|
405
660
|
diagnostics: Diagnostics,
|
|
406
|
-
|
|
407
|
-
|
|
661
|
+
configPath: string | undefined,
|
|
662
|
+
topLevelEnv: RawEnvironment
|
|
408
663
|
): Environment;
|
|
409
664
|
/**
|
|
410
665
|
* Validate the named environment configuration and return the normalized values.
|
|
411
666
|
*/
|
|
412
667
|
function normalizeAndValidateEnvironment(
|
|
413
668
|
diagnostics: Diagnostics,
|
|
669
|
+
configPath: string | undefined,
|
|
414
670
|
rawEnv: RawEnvironment,
|
|
415
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
416
671
|
envName: string,
|
|
417
|
-
|
|
672
|
+
topLevelEnv: Environment,
|
|
673
|
+
isLegacyEnv: boolean,
|
|
418
674
|
rawConfig: RawConfig
|
|
419
675
|
): Environment;
|
|
420
676
|
function normalizeAndValidateEnvironment(
|
|
421
677
|
diagnostics: Diagnostics,
|
|
678
|
+
configPath: string | undefined,
|
|
422
679
|
rawEnv: RawEnvironment,
|
|
423
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
424
680
|
envName = "top level",
|
|
425
|
-
|
|
681
|
+
topLevelEnv?: Environment | undefined,
|
|
682
|
+
isLegacyEnv?: boolean,
|
|
426
683
|
rawConfig?: RawConfig | undefined
|
|
427
684
|
): Environment {
|
|
428
685
|
deprecated(
|
|
@@ -461,44 +718,41 @@ function normalizeAndValidateEnvironment(
|
|
|
461
718
|
|
|
462
719
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
463
720
|
|
|
464
|
-
const route =
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
isString,
|
|
470
|
-
undefined
|
|
471
|
-
);
|
|
472
|
-
const routes = inheritable(
|
|
721
|
+
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
722
|
+
|
|
723
|
+
const routes = validateRoutes(diagnostics, topLevelEnv, rawEnv);
|
|
724
|
+
|
|
725
|
+
const workers_dev = inheritable(
|
|
473
726
|
diagnostics,
|
|
474
|
-
|
|
727
|
+
topLevelEnv,
|
|
475
728
|
rawEnv,
|
|
476
|
-
"
|
|
477
|
-
|
|
729
|
+
"workers_dev",
|
|
730
|
+
isBoolean,
|
|
478
731
|
undefined
|
|
479
732
|
);
|
|
480
|
-
|
|
733
|
+
|
|
734
|
+
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
481
735
|
diagnostics,
|
|
482
|
-
config,
|
|
483
736
|
rawEnv,
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
!(routes || route)
|
|
737
|
+
rawEnv.build ?? topLevelEnv?.build ?? {},
|
|
738
|
+
configPath
|
|
487
739
|
);
|
|
488
740
|
|
|
489
741
|
const environment: Environment = {
|
|
490
742
|
// Inherited fields
|
|
491
|
-
account_id:
|
|
743
|
+
account_id: inheritableInLegacyEnvironments(
|
|
492
744
|
diagnostics,
|
|
493
|
-
|
|
745
|
+
isLegacyEnv,
|
|
746
|
+
topLevelEnv,
|
|
494
747
|
rawEnv,
|
|
495
748
|
"account_id",
|
|
496
749
|
isString,
|
|
750
|
+
undefined,
|
|
497
751
|
undefined
|
|
498
752
|
),
|
|
499
753
|
compatibility_date: inheritable(
|
|
500
754
|
diagnostics,
|
|
501
|
-
|
|
755
|
+
topLevelEnv,
|
|
502
756
|
rawEnv,
|
|
503
757
|
"compatibility_date",
|
|
504
758
|
isString,
|
|
@@ -506,7 +760,7 @@ function normalizeAndValidateEnvironment(
|
|
|
506
760
|
),
|
|
507
761
|
compatibility_flags: inheritable(
|
|
508
762
|
diagnostics,
|
|
509
|
-
|
|
763
|
+
topLevelEnv,
|
|
510
764
|
rawEnv,
|
|
511
765
|
"compatibility_flags",
|
|
512
766
|
isStringArray,
|
|
@@ -514,7 +768,7 @@ function normalizeAndValidateEnvironment(
|
|
|
514
768
|
),
|
|
515
769
|
jsx_factory: inheritable(
|
|
516
770
|
diagnostics,
|
|
517
|
-
|
|
771
|
+
topLevelEnv,
|
|
518
772
|
rawEnv,
|
|
519
773
|
"jsx_factory",
|
|
520
774
|
isString,
|
|
@@ -522,25 +776,52 @@ function normalizeAndValidateEnvironment(
|
|
|
522
776
|
),
|
|
523
777
|
jsx_fragment: inheritable(
|
|
524
778
|
diagnostics,
|
|
525
|
-
|
|
779
|
+
topLevelEnv,
|
|
526
780
|
rawEnv,
|
|
527
781
|
"jsx_fragment",
|
|
528
782
|
isString,
|
|
529
783
|
"React.Fragment"
|
|
530
784
|
),
|
|
785
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
786
|
+
diagnostics,
|
|
787
|
+
topLevelEnv,
|
|
788
|
+
rawEnv,
|
|
789
|
+
configPath
|
|
790
|
+
),
|
|
531
791
|
rules: validateAndNormalizeRules(
|
|
532
792
|
diagnostics,
|
|
533
|
-
|
|
793
|
+
topLevelEnv,
|
|
534
794
|
rawEnv,
|
|
535
|
-
|
|
795
|
+
deprecatedUpload?.rules,
|
|
536
796
|
envName
|
|
537
797
|
),
|
|
538
|
-
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
|
+
),
|
|
539
820
|
route,
|
|
540
821
|
routes,
|
|
541
822
|
triggers: inheritable(
|
|
542
823
|
diagnostics,
|
|
543
|
-
|
|
824
|
+
topLevelEnv,
|
|
544
825
|
rawEnv,
|
|
545
826
|
"triggers",
|
|
546
827
|
isObjectWith("crons"),
|
|
@@ -548,17 +829,18 @@ function normalizeAndValidateEnvironment(
|
|
|
548
829
|
),
|
|
549
830
|
usage_model: inheritable(
|
|
550
831
|
diagnostics,
|
|
551
|
-
|
|
832
|
+
topLevelEnv,
|
|
552
833
|
rawEnv,
|
|
553
834
|
"usage_model",
|
|
554
835
|
isOneOf("bundled", "unbound"),
|
|
555
836
|
undefined
|
|
556
837
|
),
|
|
838
|
+
build,
|
|
557
839
|
workers_dev,
|
|
558
840
|
// Not inherited fields
|
|
559
841
|
vars: notInheritable(
|
|
560
842
|
diagnostics,
|
|
561
|
-
|
|
843
|
+
topLevelEnv,
|
|
562
844
|
rawConfig,
|
|
563
845
|
rawEnv,
|
|
564
846
|
envName,
|
|
@@ -568,7 +850,7 @@ function normalizeAndValidateEnvironment(
|
|
|
568
850
|
),
|
|
569
851
|
durable_objects: notInheritable(
|
|
570
852
|
diagnostics,
|
|
571
|
-
|
|
853
|
+
topLevelEnv,
|
|
572
854
|
rawConfig,
|
|
573
855
|
rawEnv,
|
|
574
856
|
envName,
|
|
@@ -580,7 +862,7 @@ function normalizeAndValidateEnvironment(
|
|
|
580
862
|
),
|
|
581
863
|
kv_namespaces: notInheritable(
|
|
582
864
|
diagnostics,
|
|
583
|
-
|
|
865
|
+
topLevelEnv,
|
|
584
866
|
rawConfig,
|
|
585
867
|
rawEnv,
|
|
586
868
|
envName,
|
|
@@ -590,7 +872,7 @@ function normalizeAndValidateEnvironment(
|
|
|
590
872
|
),
|
|
591
873
|
r2_buckets: notInheritable(
|
|
592
874
|
diagnostics,
|
|
593
|
-
|
|
875
|
+
topLevelEnv,
|
|
594
876
|
rawConfig,
|
|
595
877
|
rawEnv,
|
|
596
878
|
envName,
|
|
@@ -600,7 +882,7 @@ function normalizeAndValidateEnvironment(
|
|
|
600
882
|
),
|
|
601
883
|
unsafe: notInheritable(
|
|
602
884
|
diagnostics,
|
|
603
|
-
|
|
885
|
+
topLevelEnv,
|
|
604
886
|
rawConfig,
|
|
605
887
|
rawEnv,
|
|
606
888
|
envName,
|
|
@@ -611,19 +893,44 @@ function normalizeAndValidateEnvironment(
|
|
|
611
893
|
}
|
|
612
894
|
),
|
|
613
895
|
zone_id: rawEnv.zone_id,
|
|
896
|
+
minify: rawEnv.minify,
|
|
897
|
+
node_compat: rawEnv.node_compat,
|
|
614
898
|
};
|
|
615
899
|
|
|
616
900
|
return environment;
|
|
617
901
|
}
|
|
618
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
|
+
|
|
619
926
|
const validateAndNormalizeRules = (
|
|
620
927
|
diagnostics: Diagnostics,
|
|
621
|
-
|
|
928
|
+
topLevelEnv: Environment | undefined,
|
|
622
929
|
rawEnv: RawEnvironment,
|
|
623
930
|
deprecatedRules: Rule[] | undefined,
|
|
624
931
|
envName: string
|
|
625
932
|
): Rule[] => {
|
|
626
|
-
if (
|
|
933
|
+
if (topLevelEnv === undefined) {
|
|
627
934
|
// Only create errors/warnings for the top-level environment
|
|
628
935
|
if (rawEnv.rules && deprecatedRules) {
|
|
629
936
|
diagnostics.errors.push(
|
|
@@ -631,7 +938,7 @@ const validateAndNormalizeRules = (
|
|
|
631
938
|
);
|
|
632
939
|
} else if (deprecatedRules) {
|
|
633
940
|
diagnostics.warnings.push(
|
|
634
|
-
`
|
|
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` +
|
|
635
942
|
"```\n" +
|
|
636
943
|
TOML.stringify({ rules: deprecatedRules }) +
|
|
637
944
|
"```"
|
|
@@ -641,7 +948,7 @@ const validateAndNormalizeRules = (
|
|
|
641
948
|
|
|
642
949
|
return inheritable(
|
|
643
950
|
diagnostics,
|
|
644
|
-
|
|
951
|
+
topLevelEnv,
|
|
645
952
|
rawEnv,
|
|
646
953
|
"rules",
|
|
647
954
|
validateRules(envName),
|
|
@@ -804,7 +1111,7 @@ const validateBindingsProperty =
|
|
|
804
1111
|
diagnostics.warnings.push(
|
|
805
1112
|
`The following bindings are at the top level, but not on "env.${envName}".\n` +
|
|
806
1113
|
`This is not what you probably want, since "${field}" configuration is not inherited by environments.\n` +
|
|
807
|
-
`Please add a binding for each to "${fieldPath}.bindings"
|
|
1114
|
+
`Please add a binding for each to "${fieldPath}.bindings":\n` +
|
|
808
1115
|
missingBindings.map((name) => `- ${name}`).join("\n")
|
|
809
1116
|
);
|
|
810
1117
|
}
|
|
@@ -813,14 +1120,6 @@ const validateBindingsProperty =
|
|
|
813
1120
|
return isValid;
|
|
814
1121
|
};
|
|
815
1122
|
|
|
816
|
-
/**
|
|
817
|
-
* Get the names of the bindings collection in `value`.
|
|
818
|
-
*/
|
|
819
|
-
const getBindingNames = (value: unknown): string[] =>
|
|
820
|
-
((value as { bindings: { name: string }[] })?.bindings ?? []).map(
|
|
821
|
-
(binding) => binding.name
|
|
822
|
-
);
|
|
823
|
-
|
|
824
1123
|
/**
|
|
825
1124
|
* Check that the given field is a valid "durable_object" binding object.
|
|
826
1125
|
*/
|
|
@@ -991,7 +1290,7 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
991
1290
|
const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
992
1291
|
if (typeof value !== "object" || value === null) {
|
|
993
1292
|
diagnostics.errors.push(
|
|
994
|
-
`"
|
|
1293
|
+
`"r2_buckets" bindings should be objects, but got ${JSON.stringify(
|
|
995
1294
|
value
|
|
996
1295
|
)}`
|
|
997
1296
|
);
|
|
@@ -1025,3 +1324,101 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1025
1324
|
}
|
|
1026
1325
|
return isValid;
|
|
1027
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
|
+
};
|