wrangler 2.12.3 → 2.14.0

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.
Files changed (49) hide show
  1. package/package.json +11 -7
  2. package/src/__tests__/api-devregistry.test.ts +121 -0
  3. package/src/__tests__/api.test.ts +27 -5
  4. package/src/__tests__/configuration.test.ts +59 -12
  5. package/src/__tests__/deployments.test.ts +335 -95
  6. package/src/__tests__/helpers/msw/handlers/deployments.ts +70 -3
  7. package/src/__tests__/helpers/msw/index.ts +4 -2
  8. package/src/__tests__/index.test.ts +10 -4
  9. package/src/__tests__/jest.setup.ts +4 -0
  10. package/src/__tests__/mtls-certificates.test.ts +5 -2
  11. package/src/__tests__/pages/publish.test.ts +67 -23
  12. package/src/__tests__/publish.test.ts +138 -59
  13. package/src/__tests__/queues.test.ts +5 -2
  14. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  15. package/src/api/dev.ts +7 -18
  16. package/src/api/pages/create-worker-bundle-contents.ts +1 -0
  17. package/src/bundle.ts +19 -5
  18. package/src/config/environment.ts +27 -0
  19. package/src/config/index.ts +18 -0
  20. package/src/config/validation.ts +91 -1
  21. package/src/create-worker-upload-form.ts +18 -1
  22. package/src/d1/execute.tsx +1 -1
  23. package/src/d1/migrations/apply.tsx +2 -1
  24. package/src/deployments.ts +260 -8
  25. package/src/dev/start-server.ts +2 -8
  26. package/src/dev/use-esbuild.ts +2 -8
  27. package/src/dev-registry.ts +2 -1
  28. package/src/dev.tsx +1 -0
  29. package/src/entry.ts +18 -8
  30. package/src/index.ts +75 -22
  31. package/src/init.ts +144 -135
  32. package/src/metrics/send-event.ts +2 -1
  33. package/src/module-collection.ts +91 -25
  34. package/src/pages/functions/buildPlugin.ts +1 -0
  35. package/src/pages/functions/buildWorker.ts +2 -8
  36. package/src/publish/publish.ts +10 -26
  37. package/src/queues/cli/commands/consumer/add.ts +6 -0
  38. package/src/queues/client.ts +1 -0
  39. package/src/secret/index.ts +1 -0
  40. package/src/traverse-module-graph.ts +53 -0
  41. package/src/worker.ts +10 -0
  42. package/wrangler-dist/cli.d.ts +24 -0
  43. package/wrangler-dist/cli.js +19083 -18680
  44. package/src/__tests__/api-devregistry.test.js +0 -64
  45. package/src/__tests__/tsconfig.tsbuildinfo +0 -1
  46. package/src/miniflare-cli/tsconfig.tsbuildinfo +0 -1
  47. package/src/pages/functions/tsconfig.tsbuildinfo +0 -1
  48. package/templates/__tests__/tsconfig.tsbuildinfo +0 -1
  49. package/templates/tsconfig.tsbuildinfo +0 -1
package/src/init.ts CHANGED
@@ -19,7 +19,10 @@ import { CommandLineArgsError, printWranglerBanner } from "./index";
19
19
 
20
20
  import type { RawConfig } from "./config";
21
21
  import type { Route, SimpleRoute } from "./config/environment";
22
- import type { WorkerMetadata } from "./create-worker-upload-form";
22
+ import type {
23
+ WorkerMetadata,
24
+ WorkerMetadataBinding,
25
+ } from "./create-worker-upload-form";
23
26
  import type { PackageManager } from "./package-manager";
24
27
  import type { PackageJSON } from "./parse";
25
28
  import type {
@@ -838,140 +841,7 @@ async function getWorkerConfig(
838
841
  );
839
842
  });
840
843
 
841
- const mappedBindings = bindings
842
- .filter((binding) => (binding.type as string) !== "secret_text")
843
- // Combine the same types into {[type]: [binding]}
844
- .reduce((configObj, binding) => {
845
- // Some types have different names in wrangler.toml
846
- // I want the type safety of the binding being destructured after the case narrowing the union but type is unused
847
-
848
- switch (binding.type) {
849
- case "plain_text":
850
- {
851
- configObj.vars = {
852
- ...(configObj.vars ?? {}),
853
- [binding.name]: binding.text,
854
- };
855
- }
856
- break;
857
- case "json":
858
- {
859
- configObj.vars = {
860
- ...(configObj.vars ?? {}),
861
- name: binding.name,
862
- json: binding.json,
863
- };
864
- }
865
- break;
866
- case "kv_namespace":
867
- {
868
- configObj.kv_namespaces = [
869
- ...(configObj.kv_namespaces ?? []),
870
- { id: binding.namespace_id, binding: binding.name },
871
- ];
872
- }
873
- break;
874
- case "durable_object_namespace":
875
- {
876
- configObj.durable_objects = {
877
- bindings: [
878
- ...(configObj.durable_objects?.bindings ?? []),
879
- {
880
- name: binding.name,
881
- class_name: binding.class_name,
882
- script_name: binding.script_name,
883
- environment: binding.environment,
884
- },
885
- ],
886
- };
887
- }
888
- break;
889
- case "r2_bucket":
890
- {
891
- configObj.r2_buckets = [
892
- ...(configObj.r2_buckets ?? []),
893
- { binding: binding.name, bucket_name: binding.bucket_name },
894
- ];
895
- }
896
- break;
897
- case "service":
898
- {
899
- configObj.services = [
900
- ...(configObj.services ?? []),
901
- {
902
- binding: binding.name,
903
- service: binding.service,
904
- environment: binding.environment,
905
- },
906
- ];
907
- }
908
- break;
909
- case "analytics_engine":
910
- {
911
- configObj.analytics_engine_datasets = [
912
- ...(configObj.analytics_engine_datasets ?? []),
913
- { binding: binding.name, dataset: binding.dataset },
914
- ];
915
- }
916
- break;
917
- case "dispatch_namespace":
918
- {
919
- configObj.dispatch_namespaces = [
920
- ...(configObj.dispatch_namespaces ?? []),
921
- { binding: binding.name, namespace: binding.namespace },
922
- ];
923
- }
924
- break;
925
- case "logfwdr":
926
- {
927
- configObj.logfwdr = {
928
- // TODO: Messaging about adding schema file path
929
- schema: "",
930
- bindings: [
931
- ...(configObj.logfwdr?.bindings ?? []),
932
- { name: binding.name, destination: binding.destination },
933
- ],
934
- };
935
- }
936
- break;
937
- case "wasm_module":
938
- {
939
- configObj.wasm_modules = {
940
- ...(configObj.wasm_modules ?? {}),
941
- [binding.name]: binding.part,
942
- };
943
- }
944
- break;
945
- case "text_blob":
946
- {
947
- configObj.text_blobs = {
948
- ...(configObj.text_blobs ?? {}),
949
- [binding.name]: binding.part,
950
- };
951
- }
952
- break;
953
- case "data_blob":
954
- {
955
- configObj.data_blobs = {
956
- ...(configObj.data_blobs ?? {}),
957
- [binding.name]: binding.part,
958
- };
959
- }
960
- break;
961
- default: {
962
- // If we don't know what the type is, its an unsafe binding
963
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
964
- if (!(binding as any)?.type) break;
965
- configObj.unsafe = {
966
- bindings: [...(configObj.unsafe?.bindings ?? []), binding],
967
- metadata: configObj.unsafe?.metadata ?? undefined,
968
- };
969
- }
970
- }
971
-
972
- return configObj;
973
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
974
- }, {} as RawConfig);
844
+ const mappedBindings = mapBindings(bindings);
975
845
 
976
846
  const durableObjectClassNames = bindings
977
847
  .filter((binding) => binding.type === "durable_object_namespace")
@@ -1021,3 +891,142 @@ async function getWorkerConfig(
1021
891
  ...mappedBindings,
1022
892
  };
1023
893
  }
894
+
895
+ export function mapBindings(bindings: WorkerMetadataBinding[]): RawConfig {
896
+ return (
897
+ bindings
898
+ .filter((binding) => (binding.type as string) !== "secret_text")
899
+ // Combine the same types into {[type]: [binding]}
900
+ .reduce((configObj, binding) => {
901
+ // Some types have different names in wrangler.toml
902
+ // I want the type safety of the binding being destructured after the case narrowing the union but type is unused
903
+
904
+ switch (binding.type) {
905
+ case "plain_text":
906
+ {
907
+ configObj.vars = {
908
+ ...(configObj.vars ?? {}),
909
+ [binding.name]: binding.text,
910
+ };
911
+ }
912
+ break;
913
+ case "json":
914
+ {
915
+ configObj.vars = {
916
+ ...(configObj.vars ?? {}),
917
+ name: binding.name,
918
+ json: binding.json,
919
+ };
920
+ }
921
+ break;
922
+ case "kv_namespace":
923
+ {
924
+ configObj.kv_namespaces = [
925
+ ...(configObj.kv_namespaces ?? []),
926
+ { id: binding.namespace_id, binding: binding.name },
927
+ ];
928
+ }
929
+ break;
930
+ case "durable_object_namespace":
931
+ {
932
+ configObj.durable_objects = {
933
+ bindings: [
934
+ ...(configObj.durable_objects?.bindings ?? []),
935
+ {
936
+ name: binding.name,
937
+ class_name: binding.class_name,
938
+ script_name: binding.script_name,
939
+ environment: binding.environment,
940
+ },
941
+ ],
942
+ };
943
+ }
944
+ break;
945
+ case "r2_bucket":
946
+ {
947
+ configObj.r2_buckets = [
948
+ ...(configObj.r2_buckets ?? []),
949
+ { binding: binding.name, bucket_name: binding.bucket_name },
950
+ ];
951
+ }
952
+ break;
953
+ case "service":
954
+ {
955
+ configObj.services = [
956
+ ...(configObj.services ?? []),
957
+ {
958
+ binding: binding.name,
959
+ service: binding.service,
960
+ environment: binding.environment,
961
+ },
962
+ ];
963
+ }
964
+ break;
965
+ case "analytics_engine":
966
+ {
967
+ configObj.analytics_engine_datasets = [
968
+ ...(configObj.analytics_engine_datasets ?? []),
969
+ { binding: binding.name, dataset: binding.dataset },
970
+ ];
971
+ }
972
+ break;
973
+ case "dispatch_namespace":
974
+ {
975
+ configObj.dispatch_namespaces = [
976
+ ...(configObj.dispatch_namespaces ?? []),
977
+ { binding: binding.name, namespace: binding.namespace },
978
+ ];
979
+ }
980
+ break;
981
+ case "logfwdr":
982
+ {
983
+ configObj.logfwdr = {
984
+ // TODO: Messaging about adding schema file path
985
+ schema: "",
986
+ bindings: [
987
+ ...(configObj.logfwdr?.bindings ?? []),
988
+ { name: binding.name, destination: binding.destination },
989
+ ],
990
+ };
991
+ }
992
+ break;
993
+ case "wasm_module":
994
+ {
995
+ configObj.wasm_modules = {
996
+ ...(configObj.wasm_modules ?? {}),
997
+ [binding.name]: binding.part,
998
+ };
999
+ }
1000
+ break;
1001
+ case "text_blob":
1002
+ {
1003
+ configObj.text_blobs = {
1004
+ ...(configObj.text_blobs ?? {}),
1005
+ [binding.name]: binding.part,
1006
+ };
1007
+ }
1008
+ break;
1009
+ case "data_blob":
1010
+ {
1011
+ configObj.data_blobs = {
1012
+ ...(configObj.data_blobs ?? {}),
1013
+ [binding.name]: binding.part,
1014
+ };
1015
+ }
1016
+ break;
1017
+ default: {
1018
+ // If we don't know what the type is, its an unsafe binding
1019
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1020
+ if (!(binding as any)?.type) break;
1021
+ configObj.unsafe = {
1022
+ bindings: [...(configObj.unsafe?.bindings ?? []), binding],
1023
+ metadata: configObj.unsafe?.metadata ?? undefined,
1024
+ };
1025
+ }
1026
+ }
1027
+
1028
+ return configObj;
1029
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1030
+ }, {} as RawConfig)
1031
+ );
1032
+ }
@@ -57,7 +57,8 @@ export type EventNames =
57
57
  | "run dev (api)"
58
58
  | "run pages dev"
59
59
  | "view docs"
60
- | "view deployments";
60
+ | "view deployments"
61
+ | "rollback deployments";
61
62
 
62
63
  /**
63
64
  * Send a metrics event, with no extra properties, to Cloudflare, if usage tracking is enabled.
@@ -1,6 +1,7 @@
1
1
  import crypto from "node:crypto";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
+ import chalk from "chalk";
4
5
  import globToRegExp from "glob-to-regexp";
5
6
  import { logger } from "./logger";
6
7
  import type { Config, ConfigModuleRuleType } from "./config";
@@ -38,28 +39,8 @@ export const DEFAULT_MODULE_RULES: Config["rules"] = [
38
39
  { type: "CompiledWasm", globs: ["**/*.wasm"] },
39
40
  ];
40
41
 
41
- export default function createModuleCollector(props: {
42
- format: CfScriptFormat;
43
- rules?: Config["rules"];
44
- // a collection of "legacy" style module references, which are just file names
45
- // we will eventually deprecate this functionality, hence the verbose greppable name
46
- wrangler1xlegacyModuleReferences: {
47
- rootDirectory: string;
48
- fileNames: Set<string>;
49
- };
50
- }): {
51
- modules: CfModule[];
52
- plugin: esbuild.Plugin;
53
- } {
54
- const rules: Config["rules"] = [
55
- ...(props.rules || []),
56
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
57
- ...DEFAULT_MODULE_RULES!,
58
- ];
59
-
60
- // First, we want to add some validations to the module rules
61
- // We want to warn if rules are accidentally configured in such a way that
62
- // subsequent rules will never match because `fallthrough` hasn't been set
42
+ export function parseRules(userRules: Config["rules"] = []) {
43
+ const rules: Config["rules"] = [...userRules, ...DEFAULT_MODULE_RULES];
63
44
 
64
45
  const completedRuleLocations: Record<string, number> = {};
65
46
  let index = 0;
@@ -67,7 +48,7 @@ export default function createModuleCollector(props: {
67
48
  for (const rule of rules) {
68
49
  if (rule.type in completedRuleLocations) {
69
50
  if (rules[completedRuleLocations[rule.type]].fallthrough !== false) {
70
- if (index < (props.rules || []).length) {
51
+ if (index < userRules.length) {
71
52
  logger.warn(
72
53
  `The module rule at position ${index} (${JSON.stringify(
73
54
  rule
@@ -101,6 +82,89 @@ export default function createModuleCollector(props: {
101
82
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
102
83
  rulesToRemove.forEach((rule) => rules!.splice(rules!.indexOf(rule), 1));
103
84
 
85
+ return { rules, removedRules: rulesToRemove };
86
+ }
87
+
88
+ export async function matchFiles(
89
+ files: string[],
90
+ relativeTo: string,
91
+ {
92
+ rules,
93
+ removedRules,
94
+ }: { rules: Config["rules"]; removedRules: Config["rules"] }
95
+ ) {
96
+ const modules: CfModule[] = [];
97
+
98
+ // Deduplicate modules. This is usually a poorly specified `wrangler.toml` configuration, but duplicate modules will cause a crash at runtime
99
+ const moduleNames = new Set<string>();
100
+ for (const rule of rules) {
101
+ for (const glob of rule.globs) {
102
+ const regexp = globToRegExp(glob, {
103
+ globstar: true,
104
+ });
105
+ const newModules = await Promise.all(
106
+ files
107
+ .filter((f) => regexp.test(f))
108
+ .map(async (name) => {
109
+ const filePath = name;
110
+ const fileContent = await readFile(path.join(relativeTo, filePath));
111
+
112
+ return {
113
+ name: filePath,
114
+ content: fileContent,
115
+ type: RuleTypeToModuleType[rule.type],
116
+ };
117
+ })
118
+ );
119
+ for (const module of newModules) {
120
+ if (!moduleNames.has(module.name)) {
121
+ moduleNames.add(module.name);
122
+ modules.push(module);
123
+ } else {
124
+ logger.warn(
125
+ `Ignoring duplicate module: ${chalk.blue(
126
+ module.name
127
+ )} (${chalk.green(module.type ?? "")})`
128
+ );
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ // This is just a sanity check verifying that no files match rules that were removed
135
+ for (const rule of removedRules) {
136
+ for (const glob of rule.globs) {
137
+ const regexp = globToRegExp(glob);
138
+ for (const file of files) {
139
+ if (regexp.test(file)) {
140
+ throw new Error(
141
+ `The file ${file} matched a module rule in your configuration (${JSON.stringify(
142
+ rule
143
+ )}), but was ignored because a previous rule with the same type was not marked as \`fallthrough = true\`.`
144
+ );
145
+ }
146
+ }
147
+ }
148
+ }
149
+ return modules;
150
+ }
151
+
152
+ export default function createModuleCollector(props: {
153
+ format: CfScriptFormat;
154
+ rules?: Config["rules"];
155
+ // a collection of "legacy" style module references, which are just file names
156
+ // we will eventually deprecate this functionality, hence the verbose greppable name
157
+ wrangler1xlegacyModuleReferences: {
158
+ rootDirectory: string;
159
+ fileNames: Set<string>;
160
+ };
161
+ preserveFileNames?: boolean;
162
+ }): {
163
+ modules: CfModule[];
164
+ plugin: esbuild.Plugin;
165
+ } {
166
+ const { rules, removedRules } = parseRules(props.rules);
167
+
104
168
  const modules: CfModule[] = [];
105
169
  return {
106
170
  modules,
@@ -206,7 +270,9 @@ export default function createModuleCollector(props: {
206
270
  .createHash("sha1")
207
271
  .update(fileContent)
208
272
  .digest("hex");
209
- const fileName = `./${fileHash}-${path.basename(args.path)}`;
273
+ const fileName = props.preserveFileNames
274
+ ? filePath
275
+ : `./${fileHash}-${path.basename(args.path)}`;
210
276
 
211
277
  // add the module to the array
212
278
  modules.push({
@@ -245,7 +311,7 @@ export default function createModuleCollector(props: {
245
311
  });
246
312
  });
247
313
 
248
- rulesToRemove.forEach((rule) => {
314
+ removedRules.forEach((rule) => {
249
315
  rule.globs.forEach((glob) => {
250
316
  build.onResolve(
251
317
  { filter: globToRegExp(glob) },
@@ -28,6 +28,7 @@ export function buildPlugin({
28
28
  file: resolve(getBasePath(), "templates/pages-template-plugin.ts"),
29
29
  directory: functionsDirectory,
30
30
  format: "modules",
31
+ moduleRoot: functionsDirectory,
31
32
  },
32
33
  resolve(outdir),
33
34
  {
@@ -48,6 +48,7 @@ export function buildWorker({
48
48
  file: resolve(getBasePath(), "templates/pages-template-worker.ts"),
49
49
  directory: functionsDirectory,
50
50
  format: "modules",
51
+ moduleRoot: functionsDirectory,
51
52
  },
52
53
  outdir ? resolve(outdir) : resolve(outfile),
53
54
  {
@@ -58,10 +59,6 @@ export function buildWorker({
58
59
  watch,
59
60
  legacyNodeCompat,
60
61
  nodejsCompat,
61
- loader: {
62
- ".txt": "text",
63
- ".html": "text",
64
- },
65
62
  define: {
66
63
  __FALLBACK_SERVICE__: JSON.stringify(fallbackService),
67
64
  },
@@ -202,6 +199,7 @@ export function buildRawWorker({
202
199
  file: workerScriptPath,
203
200
  directory: resolve(directory),
204
201
  format: "modules",
202
+ moduleRoot: resolve(directory),
205
203
  },
206
204
  outdir ? resolve(outdir) : resolve(outfile),
207
205
  {
@@ -210,10 +208,6 @@ export function buildRawWorker({
210
208
  watch,
211
209
  legacyNodeCompat,
212
210
  nodejsCompat,
213
- loader: {
214
- ".txt": "text",
215
- ".html": "text",
216
- },
217
211
  define: {},
218
212
  betaD1Shims: (betaD1Shims || []).map(
219
213
  (binding) => `${D1_BETA_PREFIX}${binding}`
@@ -12,6 +12,7 @@ import {
12
12
  import { fetchListResult, fetchResult } from "../cfetch";
13
13
  import { printBindings } from "../config";
14
14
  import { createWorkerUploadForm } from "../create-worker-upload-form";
15
+ import { addHyphens } from "../deployments";
15
16
  import { confirm } from "../dialogs";
16
17
  import { getMigrationsToUpload } from "../durable";
17
18
  import { logger } from "../logger";
@@ -20,6 +21,7 @@ import { ParseError } from "../parse";
20
21
  import { getQueue, putConsumer } from "../queues/client";
21
22
  import { getWorkersDevSubdomain } from "../routes";
22
23
  import { syncAssets } from "../sites";
24
+ import traverseModuleGraph from "../traverse-module-graph";
23
25
  import { identifyD1BindingsAsBeta } from "../worker";
24
26
  import { getZoneForRoute } from "../zones";
25
27
  import type { FetchError } from "../cfetch";
@@ -30,7 +32,6 @@ import type {
30
32
  ZoneNameRoute,
31
33
  CustomDomainRoute,
32
34
  } from "../config/environment";
33
- import type { DeploymentListResult } from "../deployments";
34
35
  import type { Entry } from "../entry";
35
36
  import type { PutConsumerBody } from "../queues/client";
36
37
  import type { AssetPaths } from "../sites";
@@ -335,7 +336,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
335
336
 
336
337
  const jsxFactory = props.jsxFactory || config.jsx_factory;
337
338
  const jsxFragment = props.jsxFragment || config.jsx_fragment;
338
- const keepVars = props.keepVars ?? config.keep_vars;
339
+ const keepVars = props.keepVars || config.keep_vars;
339
340
 
340
341
  const minify = props.minify ?? config.minify;
341
342
 
@@ -401,7 +402,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
401
402
  : `/accounts/${accountId}/workers/scripts/${scriptName}`;
402
403
 
403
404
  let available_on_subdomain: boolean | undefined = undefined; // we'll set this later
404
- let scriptTag: string | null = null;
405
+ let deploymentId: string | null = null;
405
406
 
406
407
  const { format } = props.entry;
407
408
 
@@ -463,14 +464,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
463
464
  resolvedEntryPointPath,
464
465
  bundleType,
465
466
  }: Awaited<ReturnType<typeof bundleWorker>> = props.noBundle
466
- ? // we can skip the whole bundling step and mock a bundle here
467
- {
468
- modules: [],
469
- dependencies: {},
470
- resolvedEntryPointPath: props.entry.file,
471
- bundleType: props.entry.format === "modules" ? "esm" : "commonjs",
472
- stop: undefined,
473
- }
467
+ ? await traverseModuleGraph(props.entry, props.rules)
474
468
  : await bundleWorker(
475
469
  props.entry,
476
470
  typeof destination === "string" ? destination : destination.path,
@@ -541,6 +535,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
541
535
  ? { binding: "__STATIC_CONTENT", id: assets.namespace }
542
536
  : []
543
537
  ),
538
+ send_email: config.send_email,
544
539
  vars: { ...config.vars, ...props.vars },
545
540
  wasm_modules: config.wasm_modules,
546
541
  text_blobs: {
@@ -632,7 +627,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
632
627
  id: string | null;
633
628
  etag: string | null;
634
629
  pipeline_hash: string | null;
635
- tag: string | null;
630
+ deployment_id: string | null;
636
631
  }>(
637
632
  workerUrl,
638
633
  {
@@ -649,7 +644,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
649
644
  );
650
645
 
651
646
  available_on_subdomain = result.available_on_subdomain;
652
- scriptTag = result.tag;
647
+ deploymentId = addHyphens(result.deployment_id) ?? result.deployment_id;
653
648
 
654
649
  if (config.first_party_worker) {
655
650
  // Print some useful information returned after publishing
@@ -839,19 +834,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m
839
834
  logger.log("No publish targets for", workerName, formatTime(deployMs));
840
835
  }
841
836
 
842
- try {
843
- const deploymentsList = await fetchResult<DeploymentListResult>(
844
- `/accounts/${accountId}/workers/deployments/by-script/${scriptTag}`
845
- );
846
-
847
- logger.log("Current Deployment ID:", deploymentsList.latest.id);
848
- } catch (e) {
849
- if ((e as { code: number }).code === 10023) {
850
- // TODO: remove this try/catch once deployments is completely rolled out
851
- } else {
852
- throw e;
853
- }
854
- }
837
+ logger.log("Current Deployment ID:", deploymentId);
855
838
  }
856
839
 
857
840
  export function helpIfErrorIsSizeOrScriptStartup(
@@ -1060,6 +1043,7 @@ function updateQueueConsumers(config: Config): Promise<string[]>[] {
1060
1043
  max_wait_time_ms: consumer.max_batch_timeout
1061
1044
  ? 1000 * consumer.max_batch_timeout
1062
1045
  : undefined,
1046
+ max_concurrency: consumer.max_concurrency,
1063
1047
  },
1064
1048
  };
1065
1049
 
@@ -37,6 +37,11 @@ export function options(yargs: CommonYargsArgv) {
37
37
  type: "string",
38
38
  describe: "Queue to send messages that failed to be consumed",
39
39
  },
40
+ "max-concurrency": {
41
+ type: "number",
42
+ describe:
43
+ "The maximum number of concurrent consumer Worker invocations. Must be a positive integer",
44
+ },
40
45
  });
41
46
  }
42
47
 
@@ -55,6 +60,7 @@ export async function handler(
55
60
  max_wait_time_ms: args.batchTimeout // API expects milliseconds
56
61
  ? 1000 * args.batchTimeout
57
62
  : undefined,
63
+ max_concurrency: args.maxConcurrency,
58
64
  },
59
65
  dead_letter_queue: args.deadLetterQueue,
60
66
  };
@@ -90,6 +90,7 @@ export interface ConsumerSettings {
90
90
  batch_size?: number;
91
91
  max_retries?: number;
92
92
  max_wait_time_ms?: number;
93
+ max_concurrency?: number | null;
93
94
  }
94
95
 
95
96
  export interface ConsumerResponse extends PostConsumerBody {
@@ -100,6 +100,7 @@ export const secret = (secretYargs: CommonYargsArgv) => {
100
100
  },
101
101
  bindings: {
102
102
  kv_namespaces: [],
103
+ send_email: [],
103
104
  vars: {},
104
105
  durable_objects: { bindings: [] },
105
106
  queues: [],