wrangler 2.0.8 → 2.0.12

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 (67) hide show
  1. package/kv-asset-handler.js +1 -0
  2. package/package.json +3 -1
  3. package/src/__tests__/configuration.test.ts +255 -142
  4. package/src/__tests__/dev.test.tsx +88 -58
  5. package/src/__tests__/index.test.ts +2 -1
  6. package/src/__tests__/init.test.ts +3 -0
  7. package/src/__tests__/kv.test.ts +23 -2
  8. package/src/__tests__/pages.test.ts +98 -1
  9. package/src/__tests__/publish.test.ts +514 -162
  10. package/src/__tests__/whoami.test.tsx +34 -0
  11. package/src/bundle.ts +9 -5
  12. package/src/cfetch/internal.ts +6 -9
  13. package/src/config/config.ts +1 -1
  14. package/src/config/environment.ts +1 -1
  15. package/src/config/validation-helpers.ts +10 -1
  16. package/src/config/validation.ts +22 -13
  17. package/src/create-worker-preview.ts +15 -15
  18. package/src/dev/dev.tsx +32 -56
  19. package/src/dev/local.tsx +10 -7
  20. package/src/dev/remote.tsx +30 -17
  21. package/src/dev/use-esbuild.ts +1 -4
  22. package/src/index.tsx +239 -244
  23. package/src/kv.ts +1 -1
  24. package/src/pages.tsx +295 -229
  25. package/src/parse.ts +21 -1
  26. package/src/proxy.ts +19 -6
  27. package/src/publish.ts +154 -16
  28. package/src/sites.tsx +49 -18
  29. package/src/user.tsx +12 -1
  30. package/src/whoami.tsx +3 -2
  31. package/src/worker.ts +2 -1
  32. package/src/zones.ts +73 -0
  33. package/templates/static-asset-facade.js +1 -5
  34. package/wrangler-dist/cli.js +73693 -73458
  35. package/vendor/@cloudflare/kv-asset-handler/CHANGELOG.md +0 -332
  36. package/vendor/@cloudflare/kv-asset-handler/LICENSE_APACHE +0 -176
  37. package/vendor/@cloudflare/kv-asset-handler/LICENSE_MIT +0 -25
  38. package/vendor/@cloudflare/kv-asset-handler/README.md +0 -245
  39. package/vendor/@cloudflare/kv-asset-handler/dist/index.d.ts +0 -32
  40. package/vendor/@cloudflare/kv-asset-handler/dist/index.js +0 -354
  41. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.d.ts +0 -13
  42. package/vendor/@cloudflare/kv-asset-handler/dist/mocks.js +0 -148
  43. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.d.ts +0 -1
  44. package/vendor/@cloudflare/kv-asset-handler/dist/test/getAssetFromKV.js +0 -436
  45. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.d.ts +0 -1
  46. package/vendor/@cloudflare/kv-asset-handler/dist/test/mapRequestToAsset.js +0 -40
  47. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.d.ts +0 -1
  48. package/vendor/@cloudflare/kv-asset-handler/dist/test/serveSinglePageApp.js +0 -42
  49. package/vendor/@cloudflare/kv-asset-handler/dist/types.d.ts +0 -26
  50. package/vendor/@cloudflare/kv-asset-handler/dist/types.js +0 -31
  51. package/vendor/@cloudflare/kv-asset-handler/package.json +0 -52
  52. package/vendor/@cloudflare/kv-asset-handler/src/index.ts +0 -296
  53. package/vendor/@cloudflare/kv-asset-handler/src/mocks.ts +0 -136
  54. package/vendor/@cloudflare/kv-asset-handler/src/test/getAssetFromKV.ts +0 -464
  55. package/vendor/@cloudflare/kv-asset-handler/src/test/mapRequestToAsset.ts +0 -33
  56. package/vendor/@cloudflare/kv-asset-handler/src/test/serveSinglePageApp.ts +0 -42
  57. package/vendor/@cloudflare/kv-asset-handler/src/types.ts +0 -39
  58. package/vendor/wrangler-mime/CHANGELOG.md +0 -289
  59. package/vendor/wrangler-mime/LICENSE +0 -21
  60. package/vendor/wrangler-mime/Mime.js +0 -97
  61. package/vendor/wrangler-mime/README.md +0 -187
  62. package/vendor/wrangler-mime/cli.js +0 -46
  63. package/vendor/wrangler-mime/index.js +0 -4
  64. package/vendor/wrangler-mime/lite.js +0 -4
  65. package/vendor/wrangler-mime/package.json +0 -52
  66. package/vendor/wrangler-mime/types/other.js +0 -1
  67. package/vendor/wrangler-mime/types/standard.js +0 -1
package/src/index.tsx CHANGED
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { setTimeout } from "node:timers/promises";
5
5
  import TOML from "@iarna/toml";
6
6
  import chalk from "chalk";
7
+ import { watch } from "chokidar";
7
8
  import { execa } from "execa";
8
9
  import { findUp } from "find-up";
9
10
  import getPort from "get-port";
@@ -47,6 +48,7 @@ import {
47
48
  parsePackageJSON,
48
49
  parseTOML,
49
50
  readFileSync,
51
+ readFileSyncToBuffer,
50
52
  } from "./parse";
51
53
  import publish from "./publish";
52
54
  import { createR2Bucket, deleteR2Bucket, listR2Buckets } from "./r2";
@@ -66,6 +68,7 @@ import {
66
68
  requireAuth,
67
69
  } from "./user";
68
70
  import { whoami } from "./whoami";
71
+ import { getZoneIdFromHost, getZoneForRoute } from "./zones";
69
72
 
70
73
  import type { Config } from "./config";
71
74
  import type { TailCLIFilters } from "./tail";
@@ -444,7 +447,10 @@ function createCLIParser(argv: string[]) {
444
447
  yesFlag ||
445
448
  (await confirm("Would you like to use git to manage this Worker?"));
446
449
  if (shouldInitGit) {
447
- await execa("git", ["init", "--initial-branch=main"], {
450
+ await execa("git", ["init"], {
451
+ cwd: creationDirectory,
452
+ });
453
+ await execa("git", ["branch", "-m", "main"], {
448
454
  cwd: creationDirectory,
449
455
  });
450
456
  await writeFile(
@@ -1031,263 +1037,235 @@ function createCLIParser(argv: string[]) {
1031
1037
  });
1032
1038
  },
1033
1039
  async (args) => {
1034
- await printWranglerBanner();
1035
- const configPath =
1036
- (args.config as ConfigPath) ||
1037
- (args.script && findWranglerToml(path.dirname(args.script)));
1038
- const config = readConfig(configPath, args);
1039
- const entry = await getEntry(args, config, "dev");
1040
-
1041
- if (config.services && config.services.length > 0) {
1042
- logger.warn(
1043
- `This worker is bound to live services: ${config.services
1044
- .map(
1045
- (service) =>
1046
- `${service.binding} (${service.service}${
1047
- service.environment ? `@${service.environment}` : ""
1048
- })`
1049
- )
1050
- .join(", ")}`
1051
- );
1052
- }
1053
-
1054
- if (args.inspect) {
1055
- logger.warn(
1056
- "Passing --inspect is unnecessary, now you can always connect to devtools."
1057
- );
1058
- }
1059
-
1060
- if (args["experimental-public"]) {
1061
- logger.warn(
1062
- "The --experimental-public field is experimental and will change in the future."
1063
- );
1064
- }
1065
-
1066
- if (args.public) {
1067
- throw new Error(
1068
- "The --public field has been renamed to --experimental-public, and will change behaviour in the future."
1069
- );
1070
- }
1071
-
1072
- const upstreamProtocol =
1073
- args["upstream-protocol"] || config.dev.upstream_protocol;
1074
- if (upstreamProtocol === "http") {
1075
- logger.warn(
1076
- "Setting upstream-protocol to http is not currently implemented.\n" +
1077
- "If this is required in your project, please add your use case to the following issue:\n" +
1078
- "https://github.com/cloudflare/wrangler2/issues/583."
1079
- );
1080
- }
1040
+ let watcher: ReturnType<typeof watch> | undefined;
1041
+ try {
1042
+ await printWranglerBanner();
1043
+ const configPath =
1044
+ (args.config as ConfigPath) ||
1045
+ ((args.script &&
1046
+ findWranglerToml(path.dirname(args.script))) as ConfigPath);
1047
+ let config = readConfig(configPath, args);
1048
+
1049
+ if (config.configPath) {
1050
+ watcher = watch(config.configPath, {
1051
+ persistent: true,
1052
+ }).on("change", async (_event) => {
1053
+ // TODO: Do we need to handle different `_event` types differently?
1054
+ // e.g. what if the file is deleted, or added?
1055
+ config = readConfig(configPath, args);
1056
+ if (config.configPath) {
1057
+ logger.log(`${path.basename(config.configPath)} changed...`);
1058
+ rerender(await getDevReactElement(config));
1059
+ }
1060
+ });
1061
+ }
1081
1062
 
1082
- const accountId = !args.local ? await requireAuth(config) : undefined;
1063
+ const entry = await getEntry(args, config, "dev");
1083
1064
 
1084
- // TODO: if worker_dev = false and no routes, then error (only for dev)
1065
+ if (config.services && config.services.length > 0) {
1066
+ logger.warn(
1067
+ `This worker is bound to live services: ${config.services
1068
+ .map(
1069
+ (service) =>
1070
+ `${service.binding} (${service.service}${
1071
+ service.environment ? `@${service.environment}` : ""
1072
+ })`
1073
+ )
1074
+ .join(", ")}`
1075
+ );
1076
+ }
1085
1077
 
1086
- /**
1087
- * Given something that resembles a URL,
1088
- * try to extract a host from it
1089
- */
1090
- function getHost(urlLike: string): string | undefined {
1091
- // strip leading * / *.
1092
- urlLike = urlLike.replace(/^\*(\.)?/g, "");
1078
+ if (args.inspect) {
1079
+ logger.warn(
1080
+ "Passing --inspect is unnecessary, now you can always connect to devtools."
1081
+ );
1082
+ }
1093
1083
 
1094
- if (
1095
- !(urlLike.startsWith("http://") || urlLike.startsWith("https://"))
1096
- ) {
1097
- urlLike = "http://" + urlLike;
1084
+ if (args["experimental-public"]) {
1085
+ logger.warn(
1086
+ "The --experimental-public field is experimental and will change in the future."
1087
+ );
1098
1088
  }
1099
- return new URL(urlLike).host;
1100
- }
1101
1089
 
1102
- /**
1103
- * Given something that resembles a host,
1104
- * try to infer a zone id from it
1105
- */
1106
- async function getZoneId(host: string): Promise<string | undefined> {
1107
- const zones = await fetchResult<{ id: string }[]>(
1108
- `/zones`,
1109
- {},
1110
- new URLSearchParams({ name: host })
1111
- );
1112
- return zones[0]?.id;
1113
- }
1090
+ if (args["experimental-public"] && (args.site || config.site)) {
1091
+ throw new Error(
1092
+ "Cannot use --experimental-public and a Site configuration together."
1093
+ );
1094
+ }
1114
1095
 
1115
- // When we're given a host (in one of the above ways), we do 2 things:
1116
- // - We try to extract a host from it
1117
- // - We try to get a zone id from the host
1118
- //
1119
- // So it turns out it's particularly hard to get a 'valid' domain
1120
- // from a string, so we don't even try to validate TLDs, etc.
1121
- // Once we get something that looks like w.x.y.z-ish, we then try to
1122
- // get a zone id for it, by lopping off subdomains until we get a hit
1123
- // from the API. That's it!
1124
-
1125
- let zone: { host: string; id: string } | undefined;
1126
-
1127
- if (!args.local) {
1128
- const hostLike =
1129
- args.host ||
1130
- config.dev.host ||
1131
- (args.routes && args.routes[0]) ||
1132
- config.route ||
1133
- (config.routes && config.routes[0]);
1134
-
1135
- let zoneId: string | undefined =
1136
- typeof hostLike === "object" && "zone_id" in hostLike
1137
- ? hostLike.zone_id
1138
- : undefined;
1139
-
1140
- const host =
1141
- typeof hostLike === "string"
1142
- ? getHost(hostLike)
1143
- : typeof hostLike === "object"
1144
- ? "zone_name" in hostLike
1145
- ? getHost(hostLike.zone_name)
1146
- : getHost(hostLike.pattern)
1147
- : undefined;
1148
-
1149
- const hostPieces =
1150
- typeof host === "string" ? host.split(".") : undefined;
1151
-
1152
- while (!zoneId && hostPieces && hostPieces.length > 1) {
1153
- zoneId = await getZoneId(hostPieces.join("."));
1154
- hostPieces.shift();
1096
+ if (args.public) {
1097
+ throw new Error(
1098
+ "The --public field has been renamed to --experimental-public, and will change behaviour in the future."
1099
+ );
1155
1100
  }
1156
1101
 
1157
- if (host && !zoneId) {
1158
- throw new Error(`Could not find zone for ${hostLike}`);
1102
+ const upstreamProtocol =
1103
+ args["upstream-protocol"] || config.dev.upstream_protocol;
1104
+ if (upstreamProtocol === "http") {
1105
+ logger.warn(
1106
+ "Setting upstream-protocol to http is not currently implemented.\n" +
1107
+ "If this is required in your project, please add your use case to the following issue:\n" +
1108
+ "https://github.com/cloudflare/wrangler2/issues/583."
1109
+ );
1159
1110
  }
1160
1111
 
1161
- zone =
1162
- typeof zoneId === "string" && typeof host === "string"
1163
- ? {
1164
- host,
1165
- id: zoneId,
1166
- }
1167
- : undefined;
1168
- }
1112
+ // TODO: if worker_dev = false and no routes, then error (only for dev)
1169
1113
 
1170
- const nodeCompat = args.nodeCompat ?? config.node_compat;
1171
- if (nodeCompat) {
1172
- logger.warn(
1173
- "Enabling node.js compatibility mode for built-ins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details."
1174
- );
1175
- }
1114
+ // Compute zone info from the `host` and `route` args and config;
1115
+ let host = args.host || config.dev.host;
1116
+ let zoneId: string | undefined;
1176
1117
 
1177
- const bindings = {
1178
- kv_namespaces: config.kv_namespaces?.map(
1179
- ({ binding, preview_id, id: _id }) => {
1180
- // In `dev`, we make folks use a separate kv namespace called
1181
- // `preview_id` instead of `id` so that they don't
1182
- // break production data. So here we check that a `preview_id`
1183
- // has actually been configured.
1184
- // This whole block of code will be obsoleted in the future
1185
- // when we have copy-on-write for previews on edge workers.
1186
- if (!preview_id) {
1187
- // TODO: This error has to be a _lot_ better, ideally just asking
1188
- // to create a preview namespace for the user automatically
1189
- throw new Error(
1190
- `In development, you should use a separate kv namespace than the one you'd use in production. Please create a new kv namespace with "wrangler kv:namespace create <name> --preview" and add its id as preview_id to the kv_namespace "${binding}" in your wrangler.toml`
1191
- ); // Ugh, I really don't like this message very much
1192
- }
1193
- return {
1194
- binding,
1195
- id: preview_id,
1196
- };
1118
+ if (!args.local) {
1119
+ if (host) {
1120
+ zoneId = await getZoneIdFromHost(host);
1197
1121
  }
1198
- ),
1199
- // Use a copy of combinedVars since we're modifying it later
1200
- vars: getVarsForDev(config),
1201
- wasm_modules: config.wasm_modules,
1202
- text_blobs: config.text_blobs,
1203
- data_blobs: config.data_blobs,
1204
- durable_objects: config.durable_objects,
1205
- r2_buckets: config.r2_buckets?.map(
1206
- ({ binding, preview_bucket_name, bucket_name: _bucket_name }) => {
1207
- // same idea as kv namespace preview id,
1208
- // same copy-on-write TODO
1209
- if (!preview_bucket_name) {
1210
- throw new Error(
1211
- `In development, you should use a separate r2 bucket than the one you'd use in production. Please create a new r2 bucket with "wrangler r2 bucket create <name>" and add its name as preview_bucket_name to the r2_buckets "${binding}" in your wrangler.toml`
1212
- );
1122
+ const routes = args.routes || config.route || config.routes;
1123
+ if (!zoneId && routes) {
1124
+ const firstRoute = Array.isArray(routes) ? routes[0] : routes;
1125
+ const zone = await getZoneForRoute(firstRoute);
1126
+ if (zone) {
1127
+ zoneId = zone.id;
1128
+ host = zone.host;
1213
1129
  }
1214
- return {
1215
- binding,
1216
- bucket_name: preview_bucket_name,
1217
- };
1218
1130
  }
1219
- ),
1220
- services: config.services,
1221
- unsafe: config.unsafe?.bindings,
1222
- };
1131
+ }
1223
1132
 
1224
- // mask anything that was overridden in .dev.vars
1225
- // so that we don't log potential secrets into the terminal
1226
- const maskedVars = { ...bindings.vars };
1227
- for (const key of Object.keys(maskedVars)) {
1228
- if (maskedVars[key] !== config.vars[key]) {
1229
- // This means it was overridden in .dev.vars
1230
- // so let's mask it
1231
- maskedVars[key] = "(hidden)";
1133
+ const nodeCompat = args.nodeCompat ?? config.node_compat;
1134
+ if (nodeCompat) {
1135
+ logger.warn(
1136
+ "Enabling node.js compatibility mode for built-ins and globals. This is experimental and has serious tradeoffs. Please see https://github.com/ionic-team/rollup-plugin-node-polyfills/ for more details."
1137
+ );
1232
1138
  }
1233
- }
1234
1139
 
1235
- // now log all available bindings into the terminal
1236
- printBindings({
1237
- ...bindings,
1238
- vars: maskedVars,
1239
- });
1140
+ // eslint-disable-next-line no-inner-declarations
1141
+ async function getBindings(configParam: Config) {
1142
+ return {
1143
+ kv_namespaces: configParam.kv_namespaces?.map(
1144
+ ({ binding, preview_id, id: _id }) => {
1145
+ // In `dev`, we make folks use a separate kv namespace called
1146
+ // `preview_id` instead of `id` so that they don't
1147
+ // break production data. So here we check that a `preview_id`
1148
+ // has actually been configured.
1149
+ // This whole block of code will be obsoleted in the future
1150
+ // when we have copy-on-write for previews on edge workers.
1151
+ if (!preview_id) {
1152
+ // TODO: This error has to be a _lot_ better, ideally just asking
1153
+ // to create a preview namespace for the user automatically
1154
+ throw new Error(
1155
+ `In development, you should use a separate kv namespace than the one you'd use in production. Please create a new kv namespace with "wrangler kv:namespace create <name> --preview" and add its id as preview_id to the kv_namespace "${binding}" in your wrangler.toml`
1156
+ ); // Ugh, I really don't like this message very much
1157
+ }
1158
+ return {
1159
+ binding,
1160
+ id: preview_id,
1161
+ };
1162
+ }
1163
+ ),
1164
+ // Use a copy of combinedVars since we're modifying it later
1165
+ vars: getVarsForDev(configParam),
1166
+ wasm_modules: configParam.wasm_modules,
1167
+ text_blobs: configParam.text_blobs,
1168
+ data_blobs: configParam.data_blobs,
1169
+ durable_objects: configParam.durable_objects,
1170
+ r2_buckets: configParam.r2_buckets?.map(
1171
+ ({ binding, preview_bucket_name, bucket_name: _bucket_name }) => {
1172
+ // same idea as kv namespace preview id,
1173
+ // same copy-on-write TODO
1174
+ if (!preview_bucket_name) {
1175
+ throw new Error(
1176
+ `In development, you should use a separate r2 bucket than the one you'd use in production. Please create a new r2 bucket with "wrangler r2 bucket create <name>" and add its name as preview_bucket_name to the r2_buckets "${binding}" in your wrangler.toml`
1177
+ );
1178
+ }
1179
+ return {
1180
+ binding,
1181
+ bucket_name: preview_bucket_name,
1182
+ };
1183
+ }
1184
+ ),
1185
+ services: configParam.services,
1186
+ unsafe: configParam.unsafe?.bindings,
1187
+ };
1188
+ }
1240
1189
 
1241
- const { waitUntilExit } = render(
1242
- <Dev
1243
- name={getScriptName(args, config)}
1244
- entry={entry}
1245
- env={args.env}
1246
- zone={zone}
1247
- rules={getRules(config)}
1248
- legacyEnv={isLegacyEnv(config)}
1249
- minify={args.minify ?? config.minify}
1250
- nodeCompat={nodeCompat}
1251
- build={config.build || {}}
1252
- initialMode={args.local ? "local" : "remote"}
1253
- jsxFactory={args["jsx-factory"] || config.jsx_factory}
1254
- jsxFragment={args["jsx-fragment"] || config.jsx_fragment}
1255
- tsconfig={args.tsconfig ?? config.tsconfig}
1256
- upstreamProtocol={upstreamProtocol}
1257
- localProtocol={args["local-protocol"] || config.dev.local_protocol}
1258
- enableLocalPersistence={
1259
- args["experimental-enable-local-persistence"] || false
1260
- }
1261
- accountId={accountId}
1262
- assetPaths={getAssetPaths(
1263
- config,
1264
- args.site,
1265
- args.siteInclude,
1266
- args.siteExclude
1267
- )}
1268
- port={
1269
- args.port ||
1270
- config.dev.port ||
1271
- (await getPort({ port: DEFAULT_LOCAL_PORT }))
1272
- }
1273
- ip={args.ip || config.dev.ip}
1274
- inspectorPort={
1275
- args["inspector-port"] ?? (await getPort({ port: 9229 }))
1276
- }
1277
- public={args["experimental-public"]}
1278
- compatibilityDate={getDevCompatibilityDate(
1279
- config,
1280
- args["compatibility-date"]
1281
- )}
1282
- compatibilityFlags={
1283
- args["compatibility-flags"] || config.compatibility_flags
1190
+ const getLocalPort = memoizeGetPort(DEFAULT_LOCAL_PORT);
1191
+ const getInspectorPort = memoizeGetPort(9229);
1192
+
1193
+ // eslint-disable-next-line no-inner-declarations
1194
+ async function getDevReactElement(configParam: Config) {
1195
+ // now log all available bindings into the terminal
1196
+ const bindings = await getBindings(configParam);
1197
+ // mask anything that was overridden in .dev.vars
1198
+ // so that we don't log potential secrets into the terminal
1199
+ const maskedVars = { ...bindings.vars };
1200
+ for (const key of Object.keys(maskedVars)) {
1201
+ if (maskedVars[key] !== configParam.vars[key]) {
1202
+ // This means it was overridden in .dev.vars
1203
+ // so let's mask it
1204
+ maskedVars[key] = "(hidden)";
1205
+ }
1284
1206
  }
1285
- usageModel={config.usage_model}
1286
- bindings={bindings}
1287
- crons={config.triggers.crons}
1288
- />
1289
- );
1290
- await waitUntilExit();
1207
+
1208
+ printBindings({
1209
+ ...bindings,
1210
+ vars: maskedVars,
1211
+ });
1212
+
1213
+ return (
1214
+ <Dev
1215
+ name={getScriptName(args, config)}
1216
+ entry={entry}
1217
+ env={args.env}
1218
+ zone={zoneId}
1219
+ host={host}
1220
+ rules={getRules(config)}
1221
+ legacyEnv={isLegacyEnv(config)}
1222
+ minify={args.minify ?? config.minify}
1223
+ nodeCompat={nodeCompat}
1224
+ build={config.build || {}}
1225
+ initialMode={args.local ? "local" : "remote"}
1226
+ jsxFactory={args["jsx-factory"] || config.jsx_factory}
1227
+ jsxFragment={args["jsx-fragment"] || config.jsx_fragment}
1228
+ tsconfig={args.tsconfig ?? config.tsconfig}
1229
+ upstreamProtocol={upstreamProtocol}
1230
+ localProtocol={
1231
+ args["local-protocol"] || config.dev.local_protocol
1232
+ }
1233
+ enableLocalPersistence={
1234
+ args["experimental-enable-local-persistence"] || false
1235
+ }
1236
+ accountId={config.account_id}
1237
+ assetPaths={getAssetPaths(
1238
+ config,
1239
+ args["experimental-public"] || args.site,
1240
+ args.siteInclude,
1241
+ args.siteExclude
1242
+ )}
1243
+ port={args.port || config.dev.port || (await getLocalPort())}
1244
+ ip={args.ip || config.dev.ip}
1245
+ inspectorPort={
1246
+ args["inspector-port"] ?? (await getInspectorPort())
1247
+ }
1248
+ public={args["experimental-public"]}
1249
+ compatibilityDate={getDevCompatibilityDate(
1250
+ config,
1251
+ args["compatibility-date"]
1252
+ )}
1253
+ compatibilityFlags={
1254
+ args["compatibility-flags"] || config.compatibility_flags
1255
+ }
1256
+ usageModel={config.usage_model}
1257
+ bindings={bindings}
1258
+ crons={config.triggers.crons}
1259
+ />
1260
+ );
1261
+ }
1262
+ const { waitUntilExit, rerender } = render(
1263
+ await getDevReactElement(config)
1264
+ );
1265
+ await waitUntilExit();
1266
+ } finally {
1267
+ await watcher?.close();
1268
+ }
1291
1269
  }
1292
1270
  );
1293
1271
 
@@ -1413,23 +1391,29 @@ function createCLIParser(argv: string[]) {
1413
1391
  },
1414
1392
  async (args) => {
1415
1393
  await printWranglerBanner();
1394
+
1395
+ const configPath =
1396
+ (args.config as ConfigPath) ||
1397
+ (args.script && findWranglerToml(path.dirname(args.script)));
1398
+ const config = readConfig(configPath, args);
1399
+ const entry = await getEntry(args, config, "publish");
1400
+
1416
1401
  if (args["experimental-public"]) {
1417
1402
  logger.warn(
1418
1403
  "The --experimental-public field is experimental and will change in the future."
1419
1404
  );
1420
1405
  }
1406
+ if (args["experimental-public"] && (args.site || config.site)) {
1407
+ throw new Error(
1408
+ "Cannot use --experimental-public and a Site configuration together."
1409
+ );
1410
+ }
1421
1411
  if (args.public) {
1422
1412
  throw new Error(
1423
1413
  "The --public field has been renamed to --experimental-public, and will change behaviour in the future."
1424
1414
  );
1425
1415
  }
1426
1416
 
1427
- const configPath =
1428
- (args.config as ConfigPath) ||
1429
- (args.script && findWranglerToml(path.dirname(args.script)));
1430
- const config = readConfig(configPath, args);
1431
- const entry = await getEntry(args, config, "publish");
1432
-
1433
1417
  if (args.latest) {
1434
1418
  logger.warn(
1435
1419
  "Using the latest version of the Workers runtime. To silence this warning, please choose a specific version of the runtime with --compatibility-date, or add a compatibility_date to your wrangler.toml.\n"
@@ -1672,6 +1656,7 @@ function createCLIParser(argv: string[]) {
1672
1656
  rules={getRules(config)}
1673
1657
  env={args.env}
1674
1658
  zone={undefined}
1659
+ host={undefined}
1675
1660
  legacyEnv={isLegacyEnv(config)}
1676
1661
  build={config.build || {}}
1677
1662
  minify={undefined}
@@ -2288,7 +2273,7 @@ function createCLIParser(argv: string[]) {
2288
2273
  const namespaceId = getKVNamespaceId(args, config);
2289
2274
  // One of `args.path` and `args.value` must be defined
2290
2275
  const value = args.path
2291
- ? readFileSync(args.path)
2276
+ ? readFileSyncToBuffer(args.path)
2292
2277
  : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2293
2278
  args.value!;
2294
2279
 
@@ -2862,3 +2847,13 @@ function getDevCompatibilityDate(
2862
2847
  }
2863
2848
  return compatibilityDate ?? currentDate;
2864
2849
  }
2850
+
2851
+ /**
2852
+ * Avoiding calling `getPort()` multiple times by memoizing the first result.
2853
+ */
2854
+ function memoizeGetPort(defaultPort: number) {
2855
+ let portValue: number;
2856
+ return async () => {
2857
+ return portValue || (portValue = await getPort({ port: defaultPort }));
2858
+ };
2859
+ }
package/src/kv.ts CHANGED
@@ -111,7 +111,7 @@ export async function deleteKVNamespace(
111
111
  */
112
112
  export interface KeyValue {
113
113
  key: string;
114
- value: string;
114
+ value: string | Buffer;
115
115
  expiration?: number;
116
116
  expiration_ttl?: number;
117
117
  metadata?: object;