wrangler 0.0.0-e3cab74 → 0.0.0-e3ce82b
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 +43 -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 +1713 -411
- package/src/__tests__/dev.test.tsx +954 -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 +67 -2
- 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 +138 -747
- package/src/__tests__/init.test.ts +1637 -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__/package-manager.test.ts +154 -7
- package/src/__tests__/pages.test.ts +754 -0
- package/src/__tests__/parse.test.ts +8 -0
- package/src/__tests__/publish.test.ts +4374 -1025
- 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 +60 -7
- package/src/abort.d.ts +3 -0
- package/src/bundle.ts +75 -11
- package/src/cfetch/index.ts +21 -4
- package/src/cfetch/internal.ts +29 -20
- 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 +237 -23
- package/src/config/validation.ts +722 -191
- package/src/config-cache.ts +45 -0
- package/src/{api/preview.ts → create-worker-preview.ts} +65 -27
- 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 +401 -0
- package/src/dev/local.tsx +322 -0
- package/src/dev/remote.tsx +237 -0
- package/src/dev/use-esbuild.ts +118 -0
- package/src/dialogs.tsx +64 -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 +1386 -867
- 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 +59 -11
- package/src/pages.tsx +1123 -75
- package/src/parse.ts +26 -6
- package/src/proxy.ts +159 -57
- package/src/publish.ts +581 -228
- package/src/selfsigned.d.ts +29 -0
- package/src/sites.tsx +130 -45
- 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 +275 -110
- package/src/whoami.tsx +5 -3
- package/src/{api/worker.ts → worker.ts} +24 -29
- package/src/zones.ts +73 -0
- package/templates/gitignore +171 -0
- package/templates/new-worker-scheduled.js +17 -0
- package/templates/new-worker-scheduled.ts +32 -0
- package/templates/new-worker.ts +16 -1
- package/templates/static-asset-facade.js +1 -5
- package/wrangler-dist/cli.js +104803 -118375
- 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/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
- package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
- package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
- package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
- package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
- package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
- package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
- package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
- package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
- package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
- package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
- package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
- package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
- package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
- package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
- package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
- package/vendor/wrangler-mime/CHANGELOG.md +0 -289
- package/vendor/wrangler-mime/LICENSE +0 -21
- package/vendor/wrangler-mime/Mime.js +0 -97
- package/vendor/wrangler-mime/README.md +0 -187
- package/vendor/wrangler-mime/cli.js +0 -46
- package/vendor/wrangler-mime/index.js +0 -4
- package/vendor/wrangler-mime/lite.js +0 -4
- package/vendor/wrangler-mime/package.json +0 -52
- package/vendor/wrangler-mime/types/other.js +0 -1
- package/vendor/wrangler-mime/types/standard.js +0 -1
- 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,32 +223,37 @@ 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
|
-
const { command, cwd, watch_dir, upload, ...rest } = rawBuild;
|
|
230
|
+
const { command, cwd, watch_dir = "./src", upload, ...rest } = rawBuild;
|
|
154
231
|
const deprecatedUpload: DeprecatedUpload = { ...upload };
|
|
155
232
|
validateAdditionalProperties(diagnostics, "build", Object.keys(rest), []);
|
|
156
233
|
|
|
157
234
|
validateOptionalProperty(diagnostics, "build", "command", command, "string");
|
|
158
235
|
validateOptionalProperty(diagnostics, "build", "cwd", cwd, "string");
|
|
159
|
-
|
|
160
|
-
diagnostics,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
236
|
+
if (Array.isArray(watch_dir)) {
|
|
237
|
+
validateTypedArray(diagnostics, "build.watch_dir", watch_dir, "string");
|
|
238
|
+
} else {
|
|
239
|
+
validateOptionalProperty(
|
|
240
|
+
diagnostics,
|
|
241
|
+
"build",
|
|
242
|
+
"watch_dir",
|
|
243
|
+
watch_dir,
|
|
244
|
+
"string"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
166
247
|
|
|
167
248
|
deprecated(
|
|
168
249
|
diagnostics,
|
|
169
|
-
|
|
250
|
+
rawEnv,
|
|
170
251
|
"build.upload.format",
|
|
171
252
|
"The format is inferred automatically from the code.",
|
|
172
253
|
true
|
|
173
254
|
);
|
|
174
255
|
|
|
175
|
-
if (
|
|
256
|
+
if (rawEnv.main !== undefined && rawBuild.upload?.main) {
|
|
176
257
|
diagnostics.errors.push(
|
|
177
258
|
`Don't define both the \`main\` and \`build.upload.main\` fields in your configuration.\n` +
|
|
178
259
|
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
@@ -181,7 +262,7 @@ function normalizeAndValidateBuild(
|
|
|
181
262
|
} else {
|
|
182
263
|
deprecated(
|
|
183
264
|
diagnostics,
|
|
184
|
-
|
|
265
|
+
rawEnv,
|
|
185
266
|
"build.upload.main",
|
|
186
267
|
`Delete the \`build.upload.main\` and \`build.upload.dir\` fields.\n` +
|
|
187
268
|
`Then add the top level \`main\` field to your configuration file:\n` +
|
|
@@ -196,24 +277,46 @@ function normalizeAndValidateBuild(
|
|
|
196
277
|
|
|
197
278
|
deprecated(
|
|
198
279
|
diagnostics,
|
|
199
|
-
|
|
280
|
+
rawEnv,
|
|
200
281
|
"build.upload.dir",
|
|
201
282
|
`Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`,
|
|
202
283
|
true
|
|
203
284
|
);
|
|
204
285
|
}
|
|
205
286
|
|
|
206
|
-
return {
|
|
287
|
+
return {
|
|
288
|
+
command,
|
|
289
|
+
watch_dir:
|
|
290
|
+
// - `watch_dir` only matters when `command` is defined, so we apply
|
|
291
|
+
// a default only when `command` is defined
|
|
292
|
+
// - `configPath` will always be defined since `build` can only
|
|
293
|
+
// be configured in `wrangler.toml`, but who knows, that may
|
|
294
|
+
// change in the future, so we do a check anyway
|
|
295
|
+
command && configPath
|
|
296
|
+
? Array.isArray(watch_dir)
|
|
297
|
+
? watch_dir.map((dir) =>
|
|
298
|
+
path.relative(
|
|
299
|
+
process.cwd(),
|
|
300
|
+
path.join(path.dirname(configPath), `${dir}`)
|
|
301
|
+
)
|
|
302
|
+
)
|
|
303
|
+
: path.relative(
|
|
304
|
+
process.cwd(),
|
|
305
|
+
path.join(path.dirname(configPath), `${watch_dir}`)
|
|
306
|
+
)
|
|
307
|
+
: watch_dir,
|
|
308
|
+
cwd,
|
|
309
|
+
deprecatedUpload,
|
|
310
|
+
};
|
|
207
311
|
}
|
|
208
312
|
|
|
209
313
|
/**
|
|
210
314
|
* Validate the `main` field and return the normalized values.
|
|
211
315
|
*/
|
|
212
316
|
function normalizeAndValidateMainField(
|
|
213
|
-
diagnostics: Diagnostics,
|
|
214
317
|
configPath: string | undefined,
|
|
215
318
|
rawMain: string | undefined,
|
|
216
|
-
deprecatedUpload:
|
|
319
|
+
deprecatedUpload: DeprecatedUpload | undefined
|
|
217
320
|
): string | undefined {
|
|
218
321
|
const configDir = path.dirname(configPath ?? "wrangler.toml");
|
|
219
322
|
if (rawMain !== undefined) {
|
|
@@ -221,13 +324,13 @@ function normalizeAndValidateMainField(
|
|
|
221
324
|
const directory = path.resolve(configDir);
|
|
222
325
|
return path.resolve(directory, rawMain);
|
|
223
326
|
} else {
|
|
224
|
-
|
|
225
|
-
`ERROR: "main" should be a string but got ${JSON.stringify(rawMain)}`
|
|
226
|
-
);
|
|
227
|
-
return;
|
|
327
|
+
return rawMain;
|
|
228
328
|
}
|
|
229
|
-
} else if (deprecatedUpload
|
|
230
|
-
const directory = path.resolve(
|
|
329
|
+
} else if (deprecatedUpload?.main !== undefined) {
|
|
330
|
+
const directory = path.resolve(
|
|
331
|
+
configDir,
|
|
332
|
+
deprecatedUpload?.dir || "./dist"
|
|
333
|
+
);
|
|
231
334
|
return path.resolve(directory, deprecatedUpload.main);
|
|
232
335
|
} else {
|
|
233
336
|
return;
|
|
@@ -239,13 +342,14 @@ function normalizeAndValidateMainField(
|
|
|
239
342
|
*/
|
|
240
343
|
function normalizeAndValidateDev(
|
|
241
344
|
diagnostics: Diagnostics,
|
|
242
|
-
rawDev:
|
|
243
|
-
):
|
|
345
|
+
rawDev: RawDevConfig
|
|
346
|
+
): DevConfig {
|
|
244
347
|
const {
|
|
245
|
-
ip = "
|
|
246
|
-
port
|
|
348
|
+
ip = "localhost",
|
|
349
|
+
port,
|
|
247
350
|
local_protocol = "http",
|
|
248
351
|
upstream_protocol = "https",
|
|
352
|
+
host,
|
|
249
353
|
...rest
|
|
250
354
|
} = rawDev;
|
|
251
355
|
validateAdditionalProperties(diagnostics, "dev", Object.keys(rest), []);
|
|
@@ -257,16 +361,19 @@ function normalizeAndValidateDev(
|
|
|
257
361
|
"dev",
|
|
258
362
|
"local_protocol",
|
|
259
363
|
local_protocol,
|
|
260
|
-
"string"
|
|
364
|
+
"string",
|
|
365
|
+
["http", "https"]
|
|
261
366
|
);
|
|
262
367
|
validateOptionalProperty(
|
|
263
368
|
diagnostics,
|
|
264
369
|
"dev",
|
|
265
370
|
"upstream_protocol",
|
|
266
371
|
upstream_protocol,
|
|
267
|
-
"string"
|
|
372
|
+
"string",
|
|
373
|
+
["http", "https"]
|
|
268
374
|
);
|
|
269
|
-
|
|
375
|
+
validateOptionalProperty(diagnostics, "dev", "host", host, "string");
|
|
376
|
+
return { ip, port, local_protocol, upstream_protocol, host };
|
|
270
377
|
}
|
|
271
378
|
|
|
272
379
|
/**
|
|
@@ -274,7 +381,8 @@ function normalizeAndValidateDev(
|
|
|
274
381
|
*/
|
|
275
382
|
function normalizeAndValidateMigrations(
|
|
276
383
|
diagnostics: Diagnostics,
|
|
277
|
-
rawMigrations: Config["migrations"]
|
|
384
|
+
rawMigrations: Config["migrations"],
|
|
385
|
+
durableObjects: Config["durable_objects"]
|
|
278
386
|
): Config["migrations"] {
|
|
279
387
|
if (!Array.isArray(rawMigrations)) {
|
|
280
388
|
diagnostics.errors.push(
|
|
@@ -285,29 +393,38 @@ function normalizeAndValidateMigrations(
|
|
|
285
393
|
return [];
|
|
286
394
|
} else {
|
|
287
395
|
for (let i = 0; i < rawMigrations.length; i++) {
|
|
288
|
-
const
|
|
396
|
+
const { tag, new_classes, renamed_classes, deleted_classes, ...rest } =
|
|
397
|
+
rawMigrations[i];
|
|
398
|
+
|
|
399
|
+
validateAdditionalProperties(
|
|
400
|
+
diagnostics,
|
|
401
|
+
"migrations",
|
|
402
|
+
Object.keys(rest),
|
|
403
|
+
[]
|
|
404
|
+
);
|
|
405
|
+
|
|
289
406
|
validateRequiredProperty(
|
|
290
407
|
diagnostics,
|
|
291
408
|
`migrations[${i}]`,
|
|
292
409
|
`tag`,
|
|
293
|
-
|
|
410
|
+
tag,
|
|
294
411
|
"string"
|
|
295
412
|
);
|
|
296
413
|
validateOptionalTypedArray(
|
|
297
414
|
diagnostics,
|
|
298
415
|
`migrations[${i}].new_classes`,
|
|
299
|
-
|
|
416
|
+
new_classes,
|
|
300
417
|
"string"
|
|
301
418
|
);
|
|
302
|
-
if (
|
|
303
|
-
if (!Array.isArray(
|
|
419
|
+
if (renamed_classes !== undefined) {
|
|
420
|
+
if (!Array.isArray(renamed_classes)) {
|
|
304
421
|
diagnostics.errors.push(
|
|
305
|
-
`"migrations[${i}].renamed_classes"
|
|
306
|
-
|
|
422
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
423
|
+
renamed_classes
|
|
307
424
|
)}.`
|
|
308
425
|
);
|
|
309
426
|
} else if (
|
|
310
|
-
|
|
427
|
+
renamed_classes.some(
|
|
311
428
|
(c) =>
|
|
312
429
|
typeof c !== "object" ||
|
|
313
430
|
!isRequiredProperty(c, "from", "string") ||
|
|
@@ -315,8 +432,8 @@ function normalizeAndValidateMigrations(
|
|
|
315
432
|
)
|
|
316
433
|
) {
|
|
317
434
|
diagnostics.errors.push(
|
|
318
|
-
`"migrations[${i}].renamed_classes"
|
|
319
|
-
|
|
435
|
+
`Expected "migrations[${i}].renamed_classes" to be an array of "{from: string, to: string}" objects but got ${JSON.stringify(
|
|
436
|
+
renamed_classes
|
|
320
437
|
)}.`
|
|
321
438
|
);
|
|
322
439
|
}
|
|
@@ -324,10 +441,49 @@ function normalizeAndValidateMigrations(
|
|
|
324
441
|
validateOptionalTypedArray(
|
|
325
442
|
diagnostics,
|
|
326
443
|
`migrations[${i}].deleted_classes`,
|
|
327
|
-
|
|
444
|
+
deleted_classes,
|
|
328
445
|
"string"
|
|
329
446
|
);
|
|
330
447
|
}
|
|
448
|
+
|
|
449
|
+
if (
|
|
450
|
+
Array.isArray(durableObjects?.bindings) &&
|
|
451
|
+
durableObjects.bindings.length > 0
|
|
452
|
+
) {
|
|
453
|
+
// intrinsic [durable_objects] implies [migrations]
|
|
454
|
+
const exportedDurableObjects = (durableObjects.bindings || []).filter(
|
|
455
|
+
(binding) => !binding.script_name
|
|
456
|
+
);
|
|
457
|
+
if (exportedDurableObjects.length > 0 && rawMigrations.length === 0) {
|
|
458
|
+
if (
|
|
459
|
+
!exportedDurableObjects.some(
|
|
460
|
+
(exportedDurableObject) =>
|
|
461
|
+
typeof exportedDurableObject.class_name !== "string"
|
|
462
|
+
)
|
|
463
|
+
) {
|
|
464
|
+
const durableObjectClassnames = exportedDurableObjects.map(
|
|
465
|
+
(durable) => durable.class_name
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
diagnostics.warnings.push(
|
|
469
|
+
`In wrangler.toml, you have configured [durable_objects] exported by this Worker (${durableObjectClassnames.join(
|
|
470
|
+
", "
|
|
471
|
+
)}), 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:
|
|
472
|
+
|
|
473
|
+
\`\`\`
|
|
474
|
+
[[migrations]]
|
|
475
|
+
tag = "v1" # Should be unique for each entry
|
|
476
|
+
new_classes = [${durableObjectClassnames
|
|
477
|
+
.map((name) => `"${name}"`)
|
|
478
|
+
.join(", ")}]
|
|
479
|
+
\`\`\`
|
|
480
|
+
|
|
481
|
+
Refer to https://developers.cloudflare.com/workers/learning/using-durable-objects/#durable-object-migrations-in-wranglertoml for more details.`
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
331
487
|
return rawMigrations;
|
|
332
488
|
}
|
|
333
489
|
}
|
|
@@ -337,39 +493,91 @@ function normalizeAndValidateMigrations(
|
|
|
337
493
|
*/
|
|
338
494
|
function normalizeAndValidateSite(
|
|
339
495
|
diagnostics: Diagnostics,
|
|
340
|
-
|
|
496
|
+
configPath: string | undefined,
|
|
497
|
+
rawConfig: RawConfig,
|
|
498
|
+
mainEntryPoint: string | undefined
|
|
341
499
|
): Config["site"] {
|
|
342
|
-
if (
|
|
343
|
-
const {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
...rest
|
|
349
|
-
} = rawSite;
|
|
350
|
-
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), []);
|
|
500
|
+
if (rawConfig?.site !== undefined) {
|
|
501
|
+
const { bucket, include = [], exclude = [], ...rest } = rawConfig.site;
|
|
502
|
+
|
|
503
|
+
validateAdditionalProperties(diagnostics, "site", Object.keys(rest), [
|
|
504
|
+
"entry-point",
|
|
505
|
+
]);
|
|
351
506
|
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
|
|
507
|
+
validateTypedArray(diagnostics, "sites.include", include, "string");
|
|
508
|
+
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
|
|
352
509
|
validateOptionalProperty(
|
|
353
510
|
diagnostics,
|
|
354
511
|
"site",
|
|
355
|
-
"
|
|
356
|
-
|
|
512
|
+
"entry-point",
|
|
513
|
+
rawConfig.site["entry-point"],
|
|
357
514
|
"string"
|
|
358
515
|
);
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
516
|
+
|
|
517
|
+
deprecated(
|
|
518
|
+
diagnostics,
|
|
519
|
+
rawConfig,
|
|
520
|
+
`site.entry-point`,
|
|
521
|
+
`Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:\n` +
|
|
522
|
+
`\`\`\`\n` +
|
|
523
|
+
`main = "${path.join(
|
|
524
|
+
String(rawConfig.site["entry-point"]) || "workers-site",
|
|
525
|
+
path.extname(String(rawConfig.site["entry-point"]) || "workers-site")
|
|
526
|
+
? ""
|
|
527
|
+
: "index.js"
|
|
528
|
+
)}"\n` +
|
|
529
|
+
`\`\`\``,
|
|
530
|
+
false,
|
|
531
|
+
undefined,
|
|
532
|
+
"warning"
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
let siteEntryPoint = rawConfig.site["entry-point"];
|
|
536
|
+
|
|
537
|
+
if (!mainEntryPoint && !siteEntryPoint) {
|
|
538
|
+
// this means that we're defaulting to "workers-site"
|
|
539
|
+
// so let's add the deprecation warning
|
|
540
|
+
diagnostics.warnings.push(
|
|
541
|
+
`Because you've defined a [site] configuration, we're defaulting to "workers-site" for the deprecated \`site.entry-point\`field.\n` +
|
|
542
|
+
`Add the top level \`main\` field to your configuration file:\n` +
|
|
543
|
+
`\`\`\`\n` +
|
|
544
|
+
`main = "workers-site/index.js"\n` +
|
|
545
|
+
`\`\`\``
|
|
546
|
+
);
|
|
547
|
+
siteEntryPoint = "workers-site";
|
|
548
|
+
} else if (mainEntryPoint && siteEntryPoint) {
|
|
549
|
+
diagnostics.errors.push(
|
|
550
|
+
`Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.\n` +
|
|
551
|
+
`They serve the same purpose: to point to the entry-point of your worker.\n` +
|
|
552
|
+
`Delete the deprecated \`site.entry-point\` field from your config.`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (configPath && siteEntryPoint) {
|
|
557
|
+
// rewrite the path to be relative to the working directory
|
|
558
|
+
siteEntryPoint = path.relative(
|
|
559
|
+
process.cwd(),
|
|
560
|
+
path.join(path.dirname(configPath), siteEntryPoint)
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return {
|
|
565
|
+
bucket,
|
|
566
|
+
"entry-point": siteEntryPoint,
|
|
567
|
+
include,
|
|
568
|
+
exclude,
|
|
569
|
+
};
|
|
362
570
|
}
|
|
363
571
|
return undefined;
|
|
364
572
|
}
|
|
365
573
|
|
|
366
574
|
/**
|
|
367
|
-
* Map the paths of the `wasm_modules` or `
|
|
575
|
+
* Map the paths of the `wasm_modules`, `text_blobs` or `data_blobs` configuration to be relative to the current working directory.
|
|
368
576
|
*/
|
|
369
577
|
function normalizeAndValidateModulePaths(
|
|
370
578
|
diagnostics: Diagnostics,
|
|
371
579
|
configPath: string | undefined,
|
|
372
|
-
field: "wasm_modules" | "text_blobs",
|
|
580
|
+
field: "wasm_modules" | "text_blobs" | "data_blobs",
|
|
373
581
|
rawMapping: Record<string, string> | undefined
|
|
374
582
|
): Record<string, string> | undefined {
|
|
375
583
|
if (rawMapping === undefined) {
|
|
@@ -392,31 +600,147 @@ function normalizeAndValidateModulePaths(
|
|
|
392
600
|
return mapping;
|
|
393
601
|
}
|
|
394
602
|
|
|
603
|
+
/**
|
|
604
|
+
* Check whether a value has the shape of a route, which can be a string
|
|
605
|
+
* or an object that looks like {pattern: string, zone_id: string }
|
|
606
|
+
*/
|
|
607
|
+
function isValidRouteValue(item: unknown): boolean {
|
|
608
|
+
if (!item) {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
if (typeof item === "string") {
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
if (typeof item === "object") {
|
|
615
|
+
if (!hasProperty(item, "pattern") || typeof item.pattern !== "string") {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
const otherKeys = Object.keys(item).length - 1; // minus one to subtract "pattern"
|
|
620
|
+
|
|
621
|
+
const hasZoneId =
|
|
622
|
+
hasProperty(item, "zone_id") && typeof item.zone_id === "string";
|
|
623
|
+
const hasZoneName =
|
|
624
|
+
hasProperty(item, "zone_name") && typeof item.zone_name === "string";
|
|
625
|
+
const hasCustomDomainFlag =
|
|
626
|
+
hasProperty(item, "custom_domain") &&
|
|
627
|
+
typeof item.custom_domain === "boolean";
|
|
628
|
+
|
|
629
|
+
if (otherKeys === 2 && hasCustomDomainFlag && (hasZoneId || hasZoneName)) {
|
|
630
|
+
return true;
|
|
631
|
+
} else if (
|
|
632
|
+
otherKeys === 1 &&
|
|
633
|
+
(hasZoneId || hasZoneName || hasCustomDomainFlag)
|
|
634
|
+
) {
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Validate that the field is a route.
|
|
643
|
+
*/
|
|
644
|
+
const isRoute: ValidatorFn = (diagnostics, field, value) => {
|
|
645
|
+
if (value !== undefined && !isValidRouteValue(value)) {
|
|
646
|
+
diagnostics.errors.push(
|
|
647
|
+
`Expected "${field}" to be either a string, or an object with shape { pattern, custom_domain, zone_id | zone_name }, but got ${JSON.stringify(
|
|
648
|
+
value
|
|
649
|
+
)}.`
|
|
650
|
+
);
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
return true;
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Validate that the field is an array of routes.
|
|
658
|
+
*/
|
|
659
|
+
const isRouteArray: ValidatorFn = (diagnostics, field, value) => {
|
|
660
|
+
if (value === undefined) {
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
if (!Array.isArray(value)) {
|
|
664
|
+
diagnostics.errors.push(
|
|
665
|
+
`Expected "${field}" to be an array but got ${JSON.stringify(value)}.`
|
|
666
|
+
);
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
const invalidRoutes = [];
|
|
670
|
+
for (const item of value) {
|
|
671
|
+
if (!isValidRouteValue(item)) {
|
|
672
|
+
invalidRoutes.push(item);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (invalidRoutes.length > 0) {
|
|
676
|
+
diagnostics.errors.push(
|
|
677
|
+
`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(
|
|
678
|
+
invalidRoutes,
|
|
679
|
+
null,
|
|
680
|
+
2
|
|
681
|
+
)}.`
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
return invalidRoutes.length === 0;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
function validateRoute(
|
|
688
|
+
diagnostics: Diagnostics,
|
|
689
|
+
topLevelEnv: Environment | undefined,
|
|
690
|
+
rawEnv: RawEnvironment
|
|
691
|
+
): Config["route"] {
|
|
692
|
+
return inheritable(
|
|
693
|
+
diagnostics,
|
|
694
|
+
topLevelEnv,
|
|
695
|
+
rawEnv,
|
|
696
|
+
"route",
|
|
697
|
+
isRoute,
|
|
698
|
+
undefined
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function validateRoutes(
|
|
703
|
+
diagnostics: Diagnostics,
|
|
704
|
+
topLevelEnv: Environment | undefined,
|
|
705
|
+
rawEnv: RawEnvironment
|
|
706
|
+
): Config["routes"] {
|
|
707
|
+
return inheritable(
|
|
708
|
+
diagnostics,
|
|
709
|
+
topLevelEnv,
|
|
710
|
+
rawEnv,
|
|
711
|
+
"routes",
|
|
712
|
+
all(isRouteArray, isMutuallyExclusiveWith(rawEnv, "route")),
|
|
713
|
+
undefined
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
|
|
395
717
|
/**
|
|
396
718
|
* Validate top-level environment configuration and return the normalized values.
|
|
397
719
|
*/
|
|
398
720
|
function normalizeAndValidateEnvironment(
|
|
399
721
|
diagnostics: Diagnostics,
|
|
400
|
-
|
|
401
|
-
|
|
722
|
+
configPath: string | undefined,
|
|
723
|
+
topLevelEnv: RawEnvironment
|
|
402
724
|
): Environment;
|
|
403
725
|
/**
|
|
404
726
|
* Validate the named environment configuration and return the normalized values.
|
|
405
727
|
*/
|
|
406
728
|
function normalizeAndValidateEnvironment(
|
|
407
729
|
diagnostics: Diagnostics,
|
|
730
|
+
configPath: string | undefined,
|
|
408
731
|
rawEnv: RawEnvironment,
|
|
409
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
410
732
|
envName: string,
|
|
411
|
-
|
|
733
|
+
topLevelEnv: Environment,
|
|
734
|
+
isLegacyEnv: boolean,
|
|
412
735
|
rawConfig: RawConfig
|
|
413
736
|
): Environment;
|
|
414
737
|
function normalizeAndValidateEnvironment(
|
|
415
738
|
diagnostics: Diagnostics,
|
|
739
|
+
configPath: string | undefined,
|
|
416
740
|
rawEnv: RawEnvironment,
|
|
417
|
-
deprecatedRules: Environment["rules"] | undefined,
|
|
418
741
|
envName = "top level",
|
|
419
|
-
|
|
742
|
+
topLevelEnv?: Environment | undefined,
|
|
743
|
+
isLegacyEnv?: boolean,
|
|
420
744
|
rawConfig?: RawConfig | undefined
|
|
421
745
|
): Environment {
|
|
422
746
|
deprecated(
|
|
@@ -433,66 +757,48 @@ function normalizeAndValidateEnvironment(
|
|
|
433
757
|
diagnostics,
|
|
434
758
|
rawEnv,
|
|
435
759
|
"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
|
-
"```",
|
|
760
|
+
`The "experimental_services" field is no longer supported. Simply rename the [experimental_services] field to [services].`,
|
|
453
761
|
true
|
|
454
762
|
);
|
|
455
763
|
|
|
456
764
|
experimental(diagnostics, rawEnv, "unsafe");
|
|
765
|
+
experimental(diagnostics, rawEnv, "services");
|
|
457
766
|
|
|
458
|
-
const route =
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
isString,
|
|
464
|
-
undefined
|
|
465
|
-
);
|
|
466
|
-
const routes = inheritable(
|
|
767
|
+
const route = validateRoute(diagnostics, topLevelEnv, rawEnv);
|
|
768
|
+
|
|
769
|
+
const routes = validateRoutes(diagnostics, topLevelEnv, rawEnv);
|
|
770
|
+
|
|
771
|
+
const workers_dev = inheritable(
|
|
467
772
|
diagnostics,
|
|
468
|
-
|
|
773
|
+
topLevelEnv,
|
|
469
774
|
rawEnv,
|
|
470
|
-
"
|
|
471
|
-
|
|
775
|
+
"workers_dev",
|
|
776
|
+
isBoolean,
|
|
472
777
|
undefined
|
|
473
778
|
);
|
|
474
|
-
|
|
779
|
+
|
|
780
|
+
const { deprecatedUpload, ...build } = normalizeAndValidateBuild(
|
|
475
781
|
diagnostics,
|
|
476
|
-
config,
|
|
477
782
|
rawEnv,
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
!(routes || route)
|
|
783
|
+
rawEnv.build ?? topLevelEnv?.build ?? {},
|
|
784
|
+
configPath
|
|
481
785
|
);
|
|
482
786
|
|
|
483
787
|
const environment: Environment = {
|
|
484
788
|
// Inherited fields
|
|
485
|
-
account_id:
|
|
789
|
+
account_id: inheritableInLegacyEnvironments(
|
|
486
790
|
diagnostics,
|
|
487
|
-
|
|
791
|
+
isLegacyEnv,
|
|
792
|
+
topLevelEnv,
|
|
488
793
|
rawEnv,
|
|
489
794
|
"account_id",
|
|
490
795
|
isString,
|
|
796
|
+
undefined,
|
|
491
797
|
undefined
|
|
492
798
|
),
|
|
493
799
|
compatibility_date: inheritable(
|
|
494
800
|
diagnostics,
|
|
495
|
-
|
|
801
|
+
topLevelEnv,
|
|
496
802
|
rawEnv,
|
|
497
803
|
"compatibility_date",
|
|
498
804
|
isString,
|
|
@@ -500,7 +806,7 @@ function normalizeAndValidateEnvironment(
|
|
|
500
806
|
),
|
|
501
807
|
compatibility_flags: inheritable(
|
|
502
808
|
diagnostics,
|
|
503
|
-
|
|
809
|
+
topLevelEnv,
|
|
504
810
|
rawEnv,
|
|
505
811
|
"compatibility_flags",
|
|
506
812
|
isStringArray,
|
|
@@ -508,7 +814,7 @@ function normalizeAndValidateEnvironment(
|
|
|
508
814
|
),
|
|
509
815
|
jsx_factory: inheritable(
|
|
510
816
|
diagnostics,
|
|
511
|
-
|
|
817
|
+
topLevelEnv,
|
|
512
818
|
rawEnv,
|
|
513
819
|
"jsx_factory",
|
|
514
820
|
isString,
|
|
@@ -516,25 +822,52 @@ function normalizeAndValidateEnvironment(
|
|
|
516
822
|
),
|
|
517
823
|
jsx_fragment: inheritable(
|
|
518
824
|
diagnostics,
|
|
519
|
-
|
|
825
|
+
topLevelEnv,
|
|
520
826
|
rawEnv,
|
|
521
827
|
"jsx_fragment",
|
|
522
828
|
isString,
|
|
523
829
|
"React.Fragment"
|
|
524
830
|
),
|
|
831
|
+
tsconfig: validateAndNormalizeTsconfig(
|
|
832
|
+
diagnostics,
|
|
833
|
+
topLevelEnv,
|
|
834
|
+
rawEnv,
|
|
835
|
+
configPath
|
|
836
|
+
),
|
|
525
837
|
rules: validateAndNormalizeRules(
|
|
526
838
|
diagnostics,
|
|
527
|
-
|
|
839
|
+
topLevelEnv,
|
|
528
840
|
rawEnv,
|
|
529
|
-
|
|
841
|
+
deprecatedUpload?.rules,
|
|
530
842
|
envName
|
|
531
843
|
),
|
|
532
|
-
name:
|
|
844
|
+
name: inheritableInLegacyEnvironments(
|
|
845
|
+
diagnostics,
|
|
846
|
+
isLegacyEnv,
|
|
847
|
+
topLevelEnv,
|
|
848
|
+
rawEnv,
|
|
849
|
+
"name",
|
|
850
|
+
isValidName,
|
|
851
|
+
appendEnvName(envName),
|
|
852
|
+
undefined
|
|
853
|
+
),
|
|
854
|
+
main: normalizeAndValidateMainField(
|
|
855
|
+
configPath,
|
|
856
|
+
inheritable(
|
|
857
|
+
diagnostics,
|
|
858
|
+
topLevelEnv,
|
|
859
|
+
rawEnv,
|
|
860
|
+
"main",
|
|
861
|
+
isString,
|
|
862
|
+
undefined
|
|
863
|
+
),
|
|
864
|
+
deprecatedUpload
|
|
865
|
+
),
|
|
533
866
|
route,
|
|
534
867
|
routes,
|
|
535
868
|
triggers: inheritable(
|
|
536
869
|
diagnostics,
|
|
537
|
-
|
|
870
|
+
topLevelEnv,
|
|
538
871
|
rawEnv,
|
|
539
872
|
"triggers",
|
|
540
873
|
isObjectWith("crons"),
|
|
@@ -542,17 +875,18 @@ function normalizeAndValidateEnvironment(
|
|
|
542
875
|
),
|
|
543
876
|
usage_model: inheritable(
|
|
544
877
|
diagnostics,
|
|
545
|
-
|
|
878
|
+
topLevelEnv,
|
|
546
879
|
rawEnv,
|
|
547
880
|
"usage_model",
|
|
548
881
|
isOneOf("bundled", "unbound"),
|
|
549
882
|
undefined
|
|
550
883
|
),
|
|
884
|
+
build,
|
|
551
885
|
workers_dev,
|
|
552
886
|
// Not inherited fields
|
|
553
887
|
vars: notInheritable(
|
|
554
888
|
diagnostics,
|
|
555
|
-
|
|
889
|
+
topLevelEnv,
|
|
556
890
|
rawConfig,
|
|
557
891
|
rawEnv,
|
|
558
892
|
envName,
|
|
@@ -562,7 +896,7 @@ function normalizeAndValidateEnvironment(
|
|
|
562
896
|
),
|
|
563
897
|
durable_objects: notInheritable(
|
|
564
898
|
diagnostics,
|
|
565
|
-
|
|
899
|
+
topLevelEnv,
|
|
566
900
|
rawConfig,
|
|
567
901
|
rawEnv,
|
|
568
902
|
envName,
|
|
@@ -574,7 +908,7 @@ function normalizeAndValidateEnvironment(
|
|
|
574
908
|
),
|
|
575
909
|
kv_namespaces: notInheritable(
|
|
576
910
|
diagnostics,
|
|
577
|
-
|
|
911
|
+
topLevelEnv,
|
|
578
912
|
rawConfig,
|
|
579
913
|
rawEnv,
|
|
580
914
|
envName,
|
|
@@ -584,7 +918,7 @@ function normalizeAndValidateEnvironment(
|
|
|
584
918
|
),
|
|
585
919
|
r2_buckets: notInheritable(
|
|
586
920
|
diagnostics,
|
|
587
|
-
|
|
921
|
+
topLevelEnv,
|
|
588
922
|
rawConfig,
|
|
589
923
|
rawEnv,
|
|
590
924
|
envName,
|
|
@@ -592,9 +926,19 @@ function normalizeAndValidateEnvironment(
|
|
|
592
926
|
validateBindingArray(envName, validateR2Binding),
|
|
593
927
|
[]
|
|
594
928
|
),
|
|
929
|
+
services: notInheritable(
|
|
930
|
+
diagnostics,
|
|
931
|
+
topLevelEnv,
|
|
932
|
+
rawConfig,
|
|
933
|
+
rawEnv,
|
|
934
|
+
envName,
|
|
935
|
+
"services",
|
|
936
|
+
validateBindingArray(envName, validateServiceBinding),
|
|
937
|
+
[]
|
|
938
|
+
),
|
|
595
939
|
unsafe: notInheritable(
|
|
596
940
|
diagnostics,
|
|
597
|
-
|
|
941
|
+
topLevelEnv,
|
|
598
942
|
rawConfig,
|
|
599
943
|
rawEnv,
|
|
600
944
|
envName,
|
|
@@ -605,27 +949,66 @@ function normalizeAndValidateEnvironment(
|
|
|
605
949
|
}
|
|
606
950
|
),
|
|
607
951
|
zone_id: rawEnv.zone_id,
|
|
952
|
+
minify: inheritable(
|
|
953
|
+
diagnostics,
|
|
954
|
+
topLevelEnv,
|
|
955
|
+
rawEnv,
|
|
956
|
+
"minify",
|
|
957
|
+
isBoolean,
|
|
958
|
+
undefined
|
|
959
|
+
),
|
|
960
|
+
node_compat: inheritable(
|
|
961
|
+
diagnostics,
|
|
962
|
+
topLevelEnv,
|
|
963
|
+
rawEnv,
|
|
964
|
+
"node_compat",
|
|
965
|
+
isBoolean,
|
|
966
|
+
undefined
|
|
967
|
+
),
|
|
608
968
|
};
|
|
609
969
|
|
|
610
970
|
return environment;
|
|
611
971
|
}
|
|
612
972
|
|
|
973
|
+
function validateAndNormalizeTsconfig(
|
|
974
|
+
diagnostics: Diagnostics,
|
|
975
|
+
topLevelEnv: Environment | undefined,
|
|
976
|
+
rawEnv: RawEnvironment,
|
|
977
|
+
configPath: string | undefined
|
|
978
|
+
) {
|
|
979
|
+
const tsconfig = inheritable(
|
|
980
|
+
diagnostics,
|
|
981
|
+
topLevelEnv,
|
|
982
|
+
rawEnv,
|
|
983
|
+
"tsconfig",
|
|
984
|
+
isString,
|
|
985
|
+
undefined
|
|
986
|
+
);
|
|
987
|
+
|
|
988
|
+
return configPath && tsconfig
|
|
989
|
+
? path.relative(
|
|
990
|
+
process.cwd(),
|
|
991
|
+
path.join(path.dirname(configPath), tsconfig)
|
|
992
|
+
)
|
|
993
|
+
: tsconfig;
|
|
994
|
+
}
|
|
995
|
+
|
|
613
996
|
const validateAndNormalizeRules = (
|
|
614
997
|
diagnostics: Diagnostics,
|
|
615
|
-
|
|
998
|
+
topLevelEnv: Environment | undefined,
|
|
616
999
|
rawEnv: RawEnvironment,
|
|
617
1000
|
deprecatedRules: Rule[] | undefined,
|
|
618
1001
|
envName: string
|
|
619
1002
|
): Rule[] => {
|
|
620
|
-
if (
|
|
1003
|
+
if (topLevelEnv === undefined) {
|
|
621
1004
|
// Only create errors/warnings for the top-level environment
|
|
622
1005
|
if (rawEnv.rules && deprecatedRules) {
|
|
623
1006
|
diagnostics.errors.push(
|
|
624
|
-
`
|
|
1007
|
+
`You cannot configure both [rules] and [build.upload.rules] in your wrangler.toml. Delete the \`build.upload\` section.`
|
|
625
1008
|
);
|
|
626
1009
|
} else if (deprecatedRules) {
|
|
627
1010
|
diagnostics.warnings.push(
|
|
628
|
-
`
|
|
1011
|
+
`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
1012
|
"```\n" +
|
|
630
1013
|
TOML.stringify({ rules: deprecatedRules }) +
|
|
631
1014
|
"```"
|
|
@@ -635,7 +1018,7 @@ const validateAndNormalizeRules = (
|
|
|
635
1018
|
|
|
636
1019
|
return inheritable(
|
|
637
1020
|
diagnostics,
|
|
638
|
-
|
|
1021
|
+
topLevelEnv,
|
|
639
1022
|
rawEnv,
|
|
640
1023
|
"rules",
|
|
641
1024
|
validateRules(envName),
|
|
@@ -671,7 +1054,9 @@ const validateRules =
|
|
|
671
1054
|
|
|
672
1055
|
const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
673
1056
|
if (typeof value !== "object" || value === null) {
|
|
674
|
-
diagnostics.errors.push(
|
|
1057
|
+
diagnostics.errors.push(
|
|
1058
|
+
`"${field}" should be an object but got ${JSON.stringify(value)}.`
|
|
1059
|
+
);
|
|
675
1060
|
return false;
|
|
676
1061
|
}
|
|
677
1062
|
// Rules must have a type string and glob string array, and optionally a fallthrough boolean.
|
|
@@ -688,7 +1073,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
688
1073
|
])
|
|
689
1074
|
) {
|
|
690
1075
|
diagnostics.errors.push(
|
|
691
|
-
`
|
|
1076
|
+
`bindings should have a string "type" field, which contains one of "ESModule", "CommonJS", "CompiledWasm", "Text", or "Data".`
|
|
692
1077
|
);
|
|
693
1078
|
isValid = false;
|
|
694
1079
|
}
|
|
@@ -699,7 +1084,7 @@ const validateRule: ValidatorFn = (diagnostics, field, value) => {
|
|
|
699
1084
|
|
|
700
1085
|
if (!isOptionalProperty(rule, "fallthrough", "boolean")) {
|
|
701
1086
|
diagnostics.errors.push(
|
|
702
|
-
`
|
|
1087
|
+
`the field "fallthrough", when present, should be a boolean.`
|
|
703
1088
|
);
|
|
704
1089
|
isValid = false;
|
|
705
1090
|
}
|
|
@@ -796,7 +1181,7 @@ const validateBindingsProperty =
|
|
|
796
1181
|
diagnostics.warnings.push(
|
|
797
1182
|
`The following bindings are at the top level, but not on "env.${envName}".\n` +
|
|
798
1183
|
`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"
|
|
1184
|
+
`Please add a binding for each to "${fieldPath}.bindings":\n` +
|
|
800
1185
|
missingBindings.map((name) => `- ${name}`).join("\n")
|
|
801
1186
|
);
|
|
802
1187
|
}
|
|
@@ -805,42 +1190,48 @@ const validateBindingsProperty =
|
|
|
805
1190
|
return isValid;
|
|
806
1191
|
};
|
|
807
1192
|
|
|
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
1193
|
/**
|
|
817
1194
|
* Check that the given field is a valid "durable_object" binding object.
|
|
818
1195
|
*/
|
|
819
1196
|
const validateDurableObjectBinding: ValidatorFn = (
|
|
820
1197
|
diagnostics,
|
|
821
|
-
|
|
1198
|
+
field,
|
|
822
1199
|
value
|
|
823
1200
|
) => {
|
|
824
1201
|
if (typeof value !== "object" || value === null) {
|
|
825
|
-
diagnostics.errors.push(
|
|
1202
|
+
diagnostics.errors.push(
|
|
1203
|
+
`Expected "${field}" to be an object but got ${JSON.stringify(value)}`
|
|
1204
|
+
);
|
|
826
1205
|
return false;
|
|
827
1206
|
}
|
|
828
1207
|
|
|
829
|
-
// Durable Object bindings must have a name and class_name, and optionally a script_name.
|
|
1208
|
+
// Durable Object bindings must have a name and class_name, and optionally a script_name and an environment.
|
|
830
1209
|
let isValid = true;
|
|
831
1210
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
832
|
-
diagnostics.errors.push(
|
|
833
|
-
`ERROR: bindings should have a string "name" field.`
|
|
834
|
-
);
|
|
1211
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
835
1212
|
isValid = false;
|
|
836
1213
|
}
|
|
837
1214
|
if (!isRequiredProperty(value, "class_name", "string")) {
|
|
838
|
-
diagnostics.errors.push(`
|
|
1215
|
+
diagnostics.errors.push(`binding should have a string "class_name" field.`);
|
|
839
1216
|
isValid = false;
|
|
840
1217
|
}
|
|
841
1218
|
if (!isOptionalProperty(value, "script_name", "string")) {
|
|
842
1219
|
diagnostics.errors.push(
|
|
843
|
-
`
|
|
1220
|
+
`the field "script_name", when present, should be a string.`
|
|
1221
|
+
);
|
|
1222
|
+
isValid = false;
|
|
1223
|
+
}
|
|
1224
|
+
// environment requires a script_name
|
|
1225
|
+
if (!isOptionalProperty(value, "environment", "string")) {
|
|
1226
|
+
diagnostics.errors.push(
|
|
1227
|
+
`the field "environment", when present, should be a string.`
|
|
1228
|
+
);
|
|
1229
|
+
isValid = false;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
if ("environment" in value && !("script_name" in value)) {
|
|
1233
|
+
diagnostics.errors.push(
|
|
1234
|
+
`binding should have a "script_name" field if "environment" is present.`
|
|
844
1235
|
);
|
|
845
1236
|
isValid = false;
|
|
846
1237
|
}
|
|
@@ -853,24 +1244,31 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
853
1244
|
*
|
|
854
1245
|
* TODO: further validation of known unsafe bindings.
|
|
855
1246
|
*/
|
|
856
|
-
const validateUnsafeBinding: ValidatorFn = (diagnostics,
|
|
1247
|
+
const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
857
1248
|
if (typeof value !== "object" || value === null) {
|
|
858
|
-
diagnostics.errors.push(
|
|
1249
|
+
diagnostics.errors.push(
|
|
1250
|
+
`Expected ${field} to be an object but got ${JSON.stringify(value)}.`
|
|
1251
|
+
);
|
|
859
1252
|
return false;
|
|
860
1253
|
}
|
|
861
1254
|
|
|
862
1255
|
let isValid = true;
|
|
863
1256
|
// Unsafe bindings must have a name and type.
|
|
864
1257
|
if (!isRequiredProperty(value, "name", "string")) {
|
|
865
|
-
diagnostics.errors.push(`
|
|
1258
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
866
1259
|
isValid = false;
|
|
867
1260
|
}
|
|
868
1261
|
if (isRequiredProperty(value, "type", "string")) {
|
|
869
1262
|
const safeBindings = [
|
|
870
1263
|
"plain_text",
|
|
871
1264
|
"json",
|
|
1265
|
+
"wasm_module",
|
|
1266
|
+
"data_blob",
|
|
1267
|
+
"text_blob",
|
|
872
1268
|
"kv_namespace",
|
|
873
1269
|
"durable_object_namespace",
|
|
1270
|
+
"r2_bucket",
|
|
1271
|
+
"service",
|
|
874
1272
|
];
|
|
875
1273
|
|
|
876
1274
|
if (safeBindings.includes(value.type)) {
|
|
@@ -881,7 +1279,7 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, _field, value) => {
|
|
|
881
1279
|
);
|
|
882
1280
|
}
|
|
883
1281
|
} else {
|
|
884
|
-
diagnostics.errors.push(`
|
|
1282
|
+
diagnostics.errors.push(`binding should have a string "type" field.`);
|
|
885
1283
|
isValid = false;
|
|
886
1284
|
}
|
|
887
1285
|
return isValid;
|
|
@@ -981,7 +1379,7 @@ const validateKVBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
981
1379
|
const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
982
1380
|
if (typeof value !== "object" || value === null) {
|
|
983
1381
|
diagnostics.errors.push(
|
|
984
|
-
`"
|
|
1382
|
+
`"r2_buckets" bindings should be objects, but got ${JSON.stringify(
|
|
985
1383
|
value
|
|
986
1384
|
)}`
|
|
987
1385
|
);
|
|
@@ -1015,3 +1413,136 @@ const validateR2Binding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1015
1413
|
}
|
|
1016
1414
|
return isValid;
|
|
1017
1415
|
};
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* Check that bindings whose names might conflict, don't.
|
|
1419
|
+
*
|
|
1420
|
+
* We don't want to have, for example, a KV namespace named "DATA"
|
|
1421
|
+
* and a Durable Object also named "DATA". Then it would be ambiguous
|
|
1422
|
+
* what exactly would live at `env.DATA` (or in the case of service-workers,
|
|
1423
|
+
* the `DATA` global).
|
|
1424
|
+
*/
|
|
1425
|
+
const validateBindingsHaveUniqueNames = (
|
|
1426
|
+
diagnostics: Diagnostics,
|
|
1427
|
+
{
|
|
1428
|
+
durable_objects,
|
|
1429
|
+
kv_namespaces,
|
|
1430
|
+
r2_buckets,
|
|
1431
|
+
text_blobs,
|
|
1432
|
+
unsafe,
|
|
1433
|
+
vars,
|
|
1434
|
+
wasm_modules,
|
|
1435
|
+
data_blobs,
|
|
1436
|
+
}: Partial<Config>
|
|
1437
|
+
): boolean => {
|
|
1438
|
+
let hasDuplicates = false;
|
|
1439
|
+
|
|
1440
|
+
const bindingsGroupedByType = {
|
|
1441
|
+
"Durable Object": getBindingNames(durable_objects),
|
|
1442
|
+
"KV Namespace": getBindingNames(kv_namespaces),
|
|
1443
|
+
"R2 Bucket": getBindingNames(r2_buckets),
|
|
1444
|
+
"Text Blob": getBindingNames(text_blobs),
|
|
1445
|
+
Unsafe: getBindingNames(unsafe),
|
|
1446
|
+
"Environment Variable": getBindingNames(vars),
|
|
1447
|
+
"WASM Module": getBindingNames(wasm_modules),
|
|
1448
|
+
"Data Blob": getBindingNames(data_blobs),
|
|
1449
|
+
} as Record<string, string[]>;
|
|
1450
|
+
|
|
1451
|
+
const bindingsGroupedByName: Record<string, string[]> = {};
|
|
1452
|
+
|
|
1453
|
+
for (const bindingType in bindingsGroupedByType) {
|
|
1454
|
+
const bindingNames = bindingsGroupedByType[bindingType];
|
|
1455
|
+
|
|
1456
|
+
for (const bindingName of bindingNames) {
|
|
1457
|
+
if (!(bindingName in bindingsGroupedByName)) {
|
|
1458
|
+
bindingsGroupedByName[bindingName] = [];
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
bindingsGroupedByName[bindingName].push(bindingType);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
for (const bindingName in bindingsGroupedByName) {
|
|
1466
|
+
const bindingTypes = bindingsGroupedByName[bindingName];
|
|
1467
|
+
if (bindingTypes.length < 2) {
|
|
1468
|
+
// there's only one (or zero) binding(s) with this name, which is fine, actually
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
hasDuplicates = true;
|
|
1473
|
+
|
|
1474
|
+
// there's two types of duplicates we want to look for:
|
|
1475
|
+
// - bindings with the same name of the same type (e.g. two Durable Objects both named "OBJ")
|
|
1476
|
+
// - bindings with the same name of different types (a KV namespace and DO both named "DATA")
|
|
1477
|
+
|
|
1478
|
+
const sameType = bindingTypes
|
|
1479
|
+
// filter once to find duplicate binding types
|
|
1480
|
+
.filter((type, i) => bindingTypes.indexOf(type) !== i)
|
|
1481
|
+
// filter twice to only get _unique_ duplicate binding types
|
|
1482
|
+
.filter(
|
|
1483
|
+
(type, i, duplicateBindingTypes) =>
|
|
1484
|
+
duplicateBindingTypes.indexOf(type) === i
|
|
1485
|
+
);
|
|
1486
|
+
|
|
1487
|
+
const differentTypes = bindingTypes.filter(
|
|
1488
|
+
(type, i) => bindingTypes.indexOf(type) === i
|
|
1489
|
+
);
|
|
1490
|
+
|
|
1491
|
+
if (differentTypes.length > 1) {
|
|
1492
|
+
// we have multiple different types using the same name
|
|
1493
|
+
diagnostics.errors.push(
|
|
1494
|
+
`${bindingName} assigned to ${ENGLISH.format(differentTypes)} bindings.`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
sameType.forEach((bindingType) => {
|
|
1499
|
+
diagnostics.errors.push(
|
|
1500
|
+
`${bindingName} assigned to multiple ${bindingType} bindings.`
|
|
1501
|
+
);
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
if (hasDuplicates) {
|
|
1506
|
+
const problem =
|
|
1507
|
+
"Bindings must have unique names, so that they can all be referenced in the worker.";
|
|
1508
|
+
const resolution = "Please change your bindings to have unique names.";
|
|
1509
|
+
diagnostics.errors.push(`${problem}\n${resolution}`);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
return !hasDuplicates;
|
|
1513
|
+
};
|
|
1514
|
+
const validateServiceBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
1515
|
+
if (typeof value !== "object" || value === null) {
|
|
1516
|
+
diagnostics.errors.push(
|
|
1517
|
+
`"services" bindings should be objects, but got ${JSON.stringify(value)}`
|
|
1518
|
+
);
|
|
1519
|
+
return false;
|
|
1520
|
+
}
|
|
1521
|
+
let isValid = true;
|
|
1522
|
+
// Service bindings must have a binding, service, and environment.
|
|
1523
|
+
if (!isRequiredProperty(value, "binding", "string")) {
|
|
1524
|
+
diagnostics.errors.push(
|
|
1525
|
+
`"${field}" bindings should have a string "binding" field but got ${JSON.stringify(
|
|
1526
|
+
value
|
|
1527
|
+
)}.`
|
|
1528
|
+
);
|
|
1529
|
+
isValid = false;
|
|
1530
|
+
}
|
|
1531
|
+
if (!isRequiredProperty(value, "service", "string")) {
|
|
1532
|
+
diagnostics.errors.push(
|
|
1533
|
+
`"${field}" bindings should have a string "service" field but got ${JSON.stringify(
|
|
1534
|
+
value
|
|
1535
|
+
)}.`
|
|
1536
|
+
);
|
|
1537
|
+
isValid = false;
|
|
1538
|
+
}
|
|
1539
|
+
if (!isOptionalProperty(value, "environment", "string")) {
|
|
1540
|
+
diagnostics.errors.push(
|
|
1541
|
+
`"${field}" bindings should have a string "environment" field but got ${JSON.stringify(
|
|
1542
|
+
value
|
|
1543
|
+
)}.`
|
|
1544
|
+
);
|
|
1545
|
+
isValid = false;
|
|
1546
|
+
}
|
|
1547
|
+
return isValid;
|
|
1548
|
+
};
|