wrangler 0.0.0-e5a3814 → 0.0.0-e61fba8

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.
@@ -0,0 +1 @@
1
+ export * from "@cloudflare/kv-asset-handler";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "0.0.0-e5a3814",
3
+ "version": "0.0.0-e61fba8",
4
4
  "author": "wrangler@cloudflare.com",
5
5
  "description": "Command-line interface for all things Cloudflare Workers",
6
6
  "bin": {
@@ -114,6 +114,7 @@
114
114
  "templates",
115
115
  "vendor",
116
116
  "import_meta_url.js",
117
+ "kv-asset-handler.js",
117
118
  "Cloudflare_CA.pem"
118
119
  ],
119
120
  "scripts": {
@@ -856,6 +856,33 @@ describe("wrangler dev", () => {
856
856
  }
857
857
  `);
858
858
  });
859
+
860
+ it("should error if --experimental-public and --site are used together", async () => {
861
+ writeWranglerToml({
862
+ main: "./index.js",
863
+ });
864
+ fs.writeFileSync("index.js", `export default {};`);
865
+ await expect(
866
+ runWrangler("dev --experimental-public abc --site xyz")
867
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
868
+ `"Cannot use --experimental-public and a Site configuration together."`
869
+ );
870
+ });
871
+
872
+ it("should error if --experimental-public and config.site are used together", async () => {
873
+ writeWranglerToml({
874
+ main: "./index.js",
875
+ site: {
876
+ bucket: "xyz",
877
+ },
878
+ });
879
+ fs.writeFileSync("index.js", `export default {};`);
880
+ await expect(
881
+ runWrangler("dev --experimental-public abc")
882
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
883
+ `"Cannot use --experimental-public and a Site configuration together."`
884
+ );
885
+ });
859
886
  });
860
887
 
861
888
  describe("--inspect", () => {
@@ -448,10 +448,11 @@ describe("wrangler", () => {
448
448
  });
449
449
 
450
450
  it("should put a key with a value loaded from a given path", async () => {
451
- writeFileSync("foo.txt", "file-contents", "utf-8");
451
+ const buf = Buffer.from("file-contents", "utf-8");
452
+ writeFileSync("foo.txt", buf);
452
453
  const requests = mockKeyPutRequest("some-namespace-id", {
453
454
  key: "my-key",
454
- value: "file-contents",
455
+ value: buf,
455
456
  });
456
457
  await runWrangler(
457
458
  "kv:key put my-key --namespace-id some-namespace-id --path foo.txt"
@@ -463,6 +464,26 @@ describe("wrangler", () => {
463
464
  expect(requests.count).toEqual(1);
464
465
  });
465
466
 
467
+ it("should put a key with a binary value loaded from a given path", async () => {
468
+ const buf = Buffer.from(
469
+ "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAiSURBVHgB7coxEQAACMPAgH/PgAM6dGwu49fA/deIBXrgAj2cAhIFT4QxAAAAAElFTkSuQmCC",
470
+ "base64"
471
+ );
472
+ writeFileSync("test.png", buf);
473
+ const requests = mockKeyPutRequest("another-namespace-id", {
474
+ key: "my-key",
475
+ value: buf,
476
+ });
477
+ await runWrangler(
478
+ "kv:key put my-key --namespace-id another-namespace-id --path test.png"
479
+ );
480
+ expect(std.out).toMatchInlineSnapshot(
481
+ `"Writing the contents of test.png to the key \\"my-key\\" on namespace another-namespace-id."`
482
+ );
483
+ expect(std.err).toMatchInlineSnapshot(`""`);
484
+ expect(requests.count).toEqual(1);
485
+ });
486
+
466
487
  it("should error if no key is provided", async () => {
467
488
  await expect(
468
489
  runWrangler("kv:key put")
@@ -1404,6 +1404,69 @@ addEventListener('fetch', event => {});`
1404
1404
  expect(std.err).toMatchInlineSnapshot(`""`);
1405
1405
  });
1406
1406
 
1407
+ it("should upload all the files in the directory specified by `--experimental-public`", async () => {
1408
+ const assets = [
1409
+ { filePath: "file-1.txt", content: "Content of file-1" },
1410
+ { filePath: "file-2.txt", content: "Content of file-2" },
1411
+ ];
1412
+ const kvNamespace = {
1413
+ title: "__test-name-workers_sites_assets",
1414
+ id: "__test-name-workers_sites_assets-id",
1415
+ };
1416
+ writeWranglerToml({
1417
+ main: "./index.js",
1418
+ });
1419
+ writeWorkerSource();
1420
+ writeAssets(assets);
1421
+ mockUploadWorkerRequest({
1422
+ expectedMainModule: "stdin.js",
1423
+ });
1424
+ mockSubDomainRequest();
1425
+ mockListKVNamespacesRequest(kvNamespace);
1426
+ mockKeyListRequest(kvNamespace.id, []);
1427
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
1428
+ await runWrangler("publish --experimental-public assets");
1429
+
1430
+ expect(std.out).toMatchInlineSnapshot(`
1431
+ "Reading file-1.txt...
1432
+ Uploading as file-1.2ca234f380.txt...
1433
+ Reading file-2.txt...
1434
+ Uploading as file-2.5938485188.txt...
1435
+ ↗️ Done syncing assets
1436
+ Uploaded test-name (TIMINGS)
1437
+ Published test-name (TIMINGS)
1438
+ test-name.test-sub-domain.workers.dev"
1439
+ `);
1440
+ expect(std.err).toMatchInlineSnapshot(`""`);
1441
+ });
1442
+
1443
+ it("should error if --experimental-public and --site are used together", async () => {
1444
+ writeWranglerToml({
1445
+ main: "./index.js",
1446
+ });
1447
+ writeWorkerSource();
1448
+ await expect(
1449
+ runWrangler("publish --experimental-public abc --site xyz")
1450
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1451
+ `"Cannot use --experimental-public and a Site configuration together."`
1452
+ );
1453
+ });
1454
+
1455
+ it("should error if --experimental-public and config.site are used together", async () => {
1456
+ writeWranglerToml({
1457
+ main: "./index.js",
1458
+ site: {
1459
+ bucket: "xyz",
1460
+ },
1461
+ });
1462
+ writeWorkerSource();
1463
+ await expect(
1464
+ runWrangler("publish --experimental-public abc")
1465
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
1466
+ `"Cannot use --experimental-public and a Site configuration together."`
1467
+ );
1468
+ });
1469
+
1407
1470
  it("should not contain backslash for assets with nested directories", async () => {
1408
1471
  const assets = [
1409
1472
  { filePath: "subdir/file-1.txt", content: "Content of file-1" },
@@ -2098,34 +2161,25 @@ addEventListener('fetch', event => {});`
2098
2161
  mockSubDomainRequest();
2099
2162
  mockListKVNamespacesRequest(kvNamespace);
2100
2163
  mockKeyListRequest(kvNamespace.id, []);
2164
+ const requests = mockUploadAssetsToKVRequest(kvNamespace.id);
2165
+
2166
+ await runWrangler("publish");
2101
2167
 
2102
2168
  // We expect this to be uploaded in 3 batches
2103
2169
  // The first batch has 11 files (88mb)
2170
+ expect(requests[0].uploads.length).toEqual(11);
2104
2171
  // The next batch has 5 files (93mb)
2172
+ expect(requests[1].uploads.length).toEqual(5);
2105
2173
  // And the last one has 4 files (98mb)
2174
+ expect(requests[2].uploads.length).toEqual(4);
2106
2175
 
2107
- // Since the bulk upload api endpoint stays the same
2108
- // We're going to have to clear the mock as soon as it's resolved
2109
- // And immediately add a mock for another one
2110
- // Welcome to a callback pyramid in 2022
2111
-
2112
- const removeFirstBulkUploadMockFn = mockUploadAssetsToKVRequest(
2113
- kvNamespace.id,
2114
- assets.slice(0, 11),
2115
- () => {
2116
- removeFirstBulkUploadMockFn();
2117
- const removeSecondBulkUploadMockFn = mockUploadAssetsToKVRequest(
2118
- kvNamespace.id,
2119
- assets.slice(11, 16),
2120
- () => {
2121
- removeSecondBulkUploadMockFn();
2122
- mockUploadAssetsToKVRequest(kvNamespace.id, assets.slice(16, 20));
2123
- }
2124
- );
2176
+ let assetIndex = 0;
2177
+ for (const request of requests) {
2178
+ for (const upload of request.uploads) {
2179
+ checkAssetUpload(assets[assetIndex], upload);
2180
+ assetIndex++;
2125
2181
  }
2126
- );
2127
-
2128
- await runWrangler("publish");
2182
+ }
2129
2183
 
2130
2184
  expect(std).toMatchInlineSnapshot(`
2131
2185
  Object {
@@ -5311,6 +5365,7 @@ function mockUploadWorkerRequest(
5311
5365
  options: {
5312
5366
  available_on_subdomain?: boolean;
5313
5367
  expectedEntry?: string;
5368
+ expectedMainModule?: string;
5314
5369
  expectedType?: "esm" | "sw";
5315
5370
  expectedBindings?: unknown;
5316
5371
  expectedModules?: Record<string, string>;
@@ -5324,6 +5379,7 @@ function mockUploadWorkerRequest(
5324
5379
  const {
5325
5380
  available_on_subdomain = true,
5326
5381
  expectedEntry,
5382
+ expectedMainModule = "index.js",
5327
5383
  expectedType = "esm",
5328
5384
  expectedBindings,
5329
5385
  expectedModules = {},
@@ -5347,6 +5403,7 @@ function mockUploadWorkerRequest(
5347
5403
  expect(envName).toEqual(env);
5348
5404
  }
5349
5405
  expect(queryParams.get("include_subdomain_availability")).toEqual("true");
5406
+ expect(queryParams.get("excludeScript")).toEqual("true");
5350
5407
  const formBody = body as FormData;
5351
5408
  if (expectedEntry !== undefined) {
5352
5409
  expect(await (formBody.get("index.js") as File).text()).toMatch(
@@ -5357,7 +5414,7 @@ function mockUploadWorkerRequest(
5357
5414
  formBody.get("metadata") as string
5358
5415
  ) as WorkerMetadata;
5359
5416
  if (expectedType === "esm") {
5360
- expect(metadata.main_module).toEqual("index.js");
5417
+ expect(metadata.main_module).toEqual(expectedMainModule);
5361
5418
  } else {
5362
5419
  expect(metadata.body_part).toEqual("index.js");
5363
5420
  }
@@ -5618,51 +5675,60 @@ function mockListKVNamespacesRequest(...namespaces: KVNamespaceInfo[]) {
5618
5675
  );
5619
5676
  }
5620
5677
 
5678
+ interface ExpectedAsset {
5679
+ filePath: string;
5680
+ content: string;
5681
+ expiration?: number;
5682
+ expiration_ttl?: number;
5683
+ }
5684
+ interface StaticAssetUpload {
5685
+ key: string;
5686
+ base64: boolean;
5687
+ value: string;
5688
+ expiration: number | undefined;
5689
+ expiration_ttl: number | undefined;
5690
+ }
5691
+
5621
5692
  /** Create a mock handler for the request that tries to do a bulk upload of assets to a KV namespace. */
5622
5693
  function mockUploadAssetsToKVRequest(
5623
5694
  expectedNamespaceId: string,
5624
- assets: {
5625
- filePath: string;
5626
- content: string;
5627
- expiration?: number;
5628
- expiration_ttl?: number;
5629
- }[],
5630
- onUpload?: () => void
5695
+ assets?: ExpectedAsset[]
5631
5696
  ) {
5632
- return setMockResponse(
5697
+ const requests: {
5698
+ uploads: StaticAssetUpload[];
5699
+ }[] = [];
5700
+ setMockResponse(
5633
5701
  "/accounts/:accountId/storage/kv/namespaces/:namespaceId/bulk",
5634
5702
  "PUT",
5635
5703
  ([_url, accountId, namespaceId], { body }) => {
5636
5704
  expect(accountId).toEqual("some-account-id");
5637
5705
  expect(namespaceId).toEqual(expectedNamespaceId);
5638
5706
  const uploads = JSON.parse(body as string);
5639
- expect(assets.length).toEqual(uploads.length);
5640
- for (let i = 0; i < uploads.length; i++) {
5641
- const asset = assets[i];
5642
- const upload = uploads[i];
5643
- // The asset key consists of:
5644
- // - the basename of the filepath
5645
- // - some hash value
5646
- // - the extension
5647
- const keyMatcher = new RegExp(
5648
- "^" +
5649
- asset.filePath
5650
- .replace(/(\.[^.]+)$/, ".[a-z0-9]+$1")
5651
- .replace(/\./g, "\\.")
5652
- );
5653
- expect(upload.key).toMatch(keyMatcher);
5654
- // The asset value is base64 encoded.
5655
- expect(upload.base64).toBe(true);
5656
- expect(Buffer.from(upload.value, "base64").toString()).toEqual(
5657
- asset.content
5658
- );
5659
- expect(upload.expiration).toEqual(asset.expiration);
5660
- expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
5707
+ if (assets) {
5708
+ expect(assets.length).toEqual(uploads.length);
5709
+ for (let i = 0; i < uploads.length; i++) {
5710
+ checkAssetUpload(assets[i], uploads[i]);
5711
+ }
5712
+ } else {
5713
+ requests.push({ uploads });
5661
5714
  }
5662
- onUpload?.();
5663
- return null;
5664
5715
  }
5665
5716
  );
5717
+ return requests;
5718
+ }
5719
+
5720
+ function checkAssetUpload(asset: ExpectedAsset, upload: StaticAssetUpload) {
5721
+ // The asset key consists of: `<basename>.<hash>.<extension>`
5722
+ const keyMatcher = new RegExp(
5723
+ "^" +
5724
+ asset.filePath.replace(/(\.[^.]+)$/, ".[a-z0-9]+$1").replace(/\./g, "\\.")
5725
+ );
5726
+ expect(upload.key).toMatch(keyMatcher);
5727
+ // The asset value is base64 encoded.
5728
+ expect(upload.base64).toBe(true);
5729
+ expect(Buffer.from(upload.value, "base64").toString()).toEqual(asset.content);
5730
+ expect(upload.expiration).toEqual(asset.expiration);
5731
+ expect(upload.expiration_ttl).toEqual(asset.expiration_ttl);
5666
5732
  }
5667
5733
 
5668
5734
  /** Create a mock handler for thr request that does a bulk delete of unused assets */
package/src/bundle.ts CHANGED
@@ -175,7 +175,14 @@ function getEntryPoint(
175
175
  path.join(__dirname, "../templates/static-asset-facade.js"),
176
176
  "utf8"
177
177
  )
178
- .replace("__ENTRY_POINT__", entryFile),
178
+ // on windows, escape backslashes in the path (`\`)
179
+ .replace("__ENTRY_POINT__", entryFile.replaceAll("\\", "\\\\"))
180
+ .replace(
181
+ "__KV_ASSET_HANDLER__",
182
+ path
183
+ .join(__dirname, "../kv-asset-handler.js")
184
+ .replaceAll("\\", "\\\\")
185
+ ),
179
186
  sourcefile: "static-asset-facade.js",
180
187
  resolveDir: path.dirname(entryFile),
181
188
  },
@@ -175,7 +175,7 @@ interface EnvironmentInheritable {
175
175
  /** The directory in which the command is executed. */
176
176
  cwd?: string;
177
177
  /** The directory to watch for changes while using wrangler dev, defaults to the current working directory */
178
- watch_dir?: string | string[] | undefined;
178
+ watch_dir?: string | string[];
179
179
  /**
180
180
  * Deprecated field previously used to configure the build and upload of the script.
181
181
  * @deprecated
@@ -227,8 +227,7 @@ function normalizeAndValidateBuild(
227
227
  rawBuild: Config["build"],
228
228
  configPath: string | undefined
229
229
  ): Config["build"] & { deprecatedUpload: DeprecatedUpload } {
230
- const { command, cwd, watch_dir: _watch_dir, upload, ...rest } = rawBuild;
231
- let { watch_dir } = rawBuild;
230
+ const { command, cwd, watch_dir = "./src", upload, ...rest } = rawBuild;
232
231
  const deprecatedUpload: DeprecatedUpload = { ...upload };
233
232
  validateAdditionalProperties(diagnostics, "build", Object.keys(rest), []);
234
233
 
@@ -285,9 +284,6 @@ function normalizeAndValidateBuild(
285
284
  );
286
285
  }
287
286
 
288
- // default watch_dir to './src'
289
- watch_dir ||= "./src";
290
-
291
287
  return {
292
288
  command,
293
289
  watch_dir:
package/src/dev/dev.tsx CHANGED
@@ -20,7 +20,6 @@ import type { Config } from "../config";
20
20
  import type { Entry } from "../entry";
21
21
  import type { AssetPaths } from "../sites";
22
22
  import type { CfWorkerInit } from "../worker";
23
- import type { EsbuildBundle } from "./use-esbuild";
24
23
 
25
24
  export type DevProps = {
26
25
  name?: string;
@@ -54,10 +53,6 @@ export type DevProps = {
54
53
  };
55
54
 
56
55
  export function DevImplementation(props: DevProps): JSX.Element {
57
- const directory = useTmpDir();
58
-
59
- useCustomBuild(props.entry, props.build);
60
-
61
56
  if (props.public && props.entry.format === "service-worker") {
62
57
  throw new Error(
63
58
  "You cannot use the service-worker format with a `public` directory."
@@ -82,37 +77,16 @@ export function DevImplementation(props: DevProps): JSX.Element {
82
77
  );
83
78
  }
84
79
 
85
- const bundle = useEsbuild({
86
- entry: props.entry,
87
- destination: directory,
88
- staticRoot: props.public,
89
- jsxFactory: props.jsxFactory,
90
- rules: props.rules,
91
- jsxFragment: props.jsxFragment,
92
- serveAssetsFromWorker: !!props.public,
93
- tsconfig: props.tsconfig,
94
- minify: props.minify,
95
- nodeCompat: props.nodeCompat,
96
- });
97
-
98
80
  // only load the UI if we're running in a supported environment
99
81
  const { isRawModeSupported } = useStdin();
100
82
  return isRawModeSupported ? (
101
- <InteractiveDevSession {...props} bundle={bundle} />
83
+ <InteractiveDevSession {...props} />
102
84
  ) : (
103
- <DevSession
104
- {...props}
105
- bundle={bundle}
106
- local={props.initialMode === "local"}
107
- />
85
+ <DevSession {...props} local={props.initialMode === "local"} />
108
86
  );
109
87
  }
110
88
 
111
- type InteractiveDevSessionProps = DevProps & {
112
- bundle: EsbuildBundle | undefined;
113
- };
114
-
115
- function InteractiveDevSession(props: InteractiveDevSessionProps) {
89
+ function InteractiveDevSession(props: DevProps) {
116
90
  const toggles = useHotkeys(
117
91
  {
118
92
  local: props.initialMode === "local",
@@ -145,13 +119,33 @@ function InteractiveDevSession(props: InteractiveDevSessionProps) {
145
119
  );
146
120
  }
147
121
 
148
- type DevSessionProps = InteractiveDevSessionProps & { local: boolean };
122
+ type DevSessionProps = DevProps & {
123
+ local: boolean;
124
+ };
149
125
 
150
126
  function DevSession(props: DevSessionProps) {
127
+ useCustomBuild(props.entry, props.build);
128
+
129
+ const directory = useTmpDir();
130
+
131
+ const bundle = useEsbuild({
132
+ entry: props.entry,
133
+ destination: directory,
134
+ staticRoot: props.public,
135
+ jsxFactory: props.jsxFactory,
136
+ rules: props.rules,
137
+ jsxFragment: props.jsxFragment,
138
+ // In dev for remote mode, we serve --experimental-assets from the local proxy before we send the request to the worker.
139
+ serveAssetsFromWorker: !!props.public && !!props.local,
140
+ tsconfig: props.tsconfig,
141
+ minify: props.minify,
142
+ nodeCompat: props.nodeCompat,
143
+ });
144
+
151
145
  return props.local ? (
152
146
  <Local
153
147
  name={props.name}
154
- bundle={props.bundle}
148
+ bundle={bundle}
155
149
  format={props.entry.format}
156
150
  compatibilityDate={props.compatibilityDate}
157
151
  localProtocol={props.localProtocol}
@@ -169,7 +163,7 @@ function DevSession(props: DevSessionProps) {
169
163
  ) : (
170
164
  <Remote
171
165
  name={props.name}
172
- bundle={props.bundle}
166
+ bundle={bundle}
173
167
  format={props.entry.format}
174
168
  accountId={props.accountId}
175
169
  bindings={props.bindings}
package/src/dev/local.tsx CHANGED
@@ -84,11 +84,6 @@ function useLocalWorker({
84
84
  abortSignal: abortController.signal,
85
85
  });
86
86
 
87
- if (publicDirectory) {
88
- throw new Error(
89
- '⎔ A "public" folder is not yet supported in local mode.'
90
- );
91
- }
92
87
  if (bindings.services && bindings.services.length > 0) {
93
88
  throw new Error(
94
89
  "⎔ Service bindings are not yet supported in local mode."
@@ -254,12 +249,16 @@ function useLocalWorker({
254
249
  process.stdout.write(data);
255
250
  });
256
251
 
252
+ // parse the node inspector url (which may be received in chunks) from stderr
253
+ let stderrData = "";
257
254
  local.current.stderr?.on("data", (data: Buffer) => {
255
+ stderrData += data.toString();
258
256
  const matches =
259
- /Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)/.exec(
260
- data.toString()
257
+ /Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)[\r|\n]/.exec(
258
+ stderrData
261
259
  );
262
260
  if (matches) {
261
+ local.current?.stderr?.removeAllListeners("data");
263
262
  setInspectorUrl(matches[1]);
264
263
  }
265
264
  });
@@ -40,6 +40,7 @@ export function Remote(props: {
40
40
  accountId: props.accountId,
41
41
  bindings: props.bindings,
42
42
  assetPaths: props.assetPaths,
43
+ public: props.public,
43
44
  port: props.port,
44
45
  compatibilityDate: props.compatibilityDate,
45
46
  compatibilityFlags: props.compatibilityFlags,
@@ -74,6 +75,7 @@ export function useWorker(props: {
74
75
  accountId: string | undefined;
75
76
  bindings: CfWorkerInit["bindings"];
76
77
  assetPaths: AssetPaths | undefined;
78
+ public: string | undefined;
77
79
  port: number;
78
80
  compatibilityDate: string | undefined;
79
81
  compatibilityFlags: string[] | undefined;
@@ -131,7 +133,7 @@ export function useWorker(props: {
131
133
  // include it in the kv namespace name regardless (since there's no
132
134
  // concept of service environments for kv namespaces yet).
133
135
  name + (!props.legacyEnv && props.env ? `-${props.env}` : ""),
134
- assetPaths,
136
+ props.public ? undefined : assetPaths,
135
137
  true,
136
138
  false
137
139
  ); // TODO: cancellable?
@@ -223,6 +225,7 @@ export function useWorker(props: {
223
225
  accountId,
224
226
  port,
225
227
  assetPaths,
228
+ props.public,
226
229
  compatibilityDate,
227
230
  compatibilityFlags,
228
231
  usageModel,
@@ -14,7 +14,6 @@ export type EsbuildBundle = {
14
14
  entry: Entry;
15
15
  type: "esm" | "commonjs";
16
16
  modules: CfModule[];
17
- serveAssetsFromWorker: boolean;
18
17
  };
19
18
 
20
19
  export function useEsbuild({
@@ -67,8 +66,7 @@ export function useEsbuild({
67
66
 
68
67
  const { resolvedEntryPointPath, bundleType, modules, stop } =
69
68
  await bundleWorker(entry, destination, {
70
- // In dev, we serve assets from the local proxy before we send the request to the worker.
71
- serveAssetsFromWorker: false,
69
+ serveAssetsFromWorker,
72
70
  jsxFactory,
73
71
  jsxFragment,
74
72
  rules,
@@ -87,7 +85,6 @@ export function useEsbuild({
87
85
  path: resolvedEntryPointPath,
88
86
  type: bundleType,
89
87
  modules,
90
- serveAssetsFromWorker,
91
88
  });
92
89
  }
93
90
 
package/src/index.tsx CHANGED
@@ -48,6 +48,7 @@ import {
48
48
  parsePackageJSON,
49
49
  parseTOML,
50
50
  readFileSync,
51
+ readFileSyncToBuffer,
51
52
  } from "./parse";
52
53
  import publish from "./publish";
53
54
  import { createR2Bucket, deleteR2Bucket, listR2Buckets } from "./r2";
@@ -1086,6 +1087,12 @@ function createCLIParser(argv: string[]) {
1086
1087
  );
1087
1088
  }
1088
1089
 
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
+ }
1095
+
1089
1096
  if (args.public) {
1090
1097
  throw new Error(
1091
1098
  "The --public field has been renamed to --experimental-public, and will change behaviour in the future."
@@ -1229,7 +1236,7 @@ function createCLIParser(argv: string[]) {
1229
1236
  accountId={config.account_id}
1230
1237
  assetPaths={getAssetPaths(
1231
1238
  config,
1232
- args.site,
1239
+ args["experimental-public"] || args.site,
1233
1240
  args.siteInclude,
1234
1241
  args.siteExclude
1235
1242
  )}
@@ -1384,23 +1391,29 @@ function createCLIParser(argv: string[]) {
1384
1391
  },
1385
1392
  async (args) => {
1386
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
+
1387
1401
  if (args["experimental-public"]) {
1388
1402
  logger.warn(
1389
1403
  "The --experimental-public field is experimental and will change in the future."
1390
1404
  );
1391
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
+ }
1392
1411
  if (args.public) {
1393
1412
  throw new Error(
1394
1413
  "The --public field has been renamed to --experimental-public, and will change behaviour in the future."
1395
1414
  );
1396
1415
  }
1397
1416
 
1398
- const configPath =
1399
- (args.config as ConfigPath) ||
1400
- (args.script && findWranglerToml(path.dirname(args.script)));
1401
- const config = readConfig(configPath, args);
1402
- const entry = await getEntry(args, config, "publish");
1403
-
1404
1417
  if (args.latest) {
1405
1418
  logger.warn(
1406
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"
@@ -2260,7 +2273,7 @@ function createCLIParser(argv: string[]) {
2260
2273
  const namespaceId = getKVNamespaceId(args, config);
2261
2274
  // One of `args.path` and `args.value` must be defined
2262
2275
  const value = args.path
2263
- ? readFileSync(args.path)
2276
+ ? readFileSyncToBuffer(args.path)
2264
2277
  : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2265
2278
  args.value!;
2266
2279
 
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;
package/src/parse.ts CHANGED
@@ -139,6 +139,25 @@ export function parseJSON<T>(input: string, file?: string): T {
139
139
  }
140
140
  }
141
141
 
142
+ /**
143
+ * Reads a file into a node Buffer.
144
+ */
145
+ export function readFileSyncToBuffer(file: string): Buffer {
146
+ try {
147
+ return fs.readFileSync(file);
148
+ } catch (err) {
149
+ const { message } = err as Error;
150
+ throw new ParseError({
151
+ text: `Could not read file: ${file}`,
152
+ notes: [
153
+ {
154
+ text: message.replace(file, resolve(file)),
155
+ },
156
+ ],
157
+ });
158
+ }
159
+ }
160
+
142
161
  /**
143
162
  * Reads a file and parses it based on its type.
144
163
  */
package/src/publish.ts CHANGED
@@ -430,7 +430,12 @@ export default async function publish(props: Props): Promise<void> {
430
430
  method: "PUT",
431
431
  body: createWorkerUploadForm(worker),
432
432
  },
433
- new URLSearchParams({ include_subdomain_availability: "true" })
433
+ new URLSearchParams({
434
+ include_subdomain_availability: "true",
435
+ // pass excludeScript so the whole body of the
436
+ // script doesn't get included in the response
437
+ excludeScript: "true",
438
+ })
434
439
  )
435
440
  ).available_on_subdomain;
436
441
  }
@@ -1,6 +1,6 @@
1
1
  // DO NOT IMPORT THIS DIRECTLY
2
2
  import worker from "__ENTRY_POINT__";
3
- import { getAssetFromKV } from "@cloudflare/kv-asset-handler";
3
+ import { getAssetFromKV } from "__KV_ASSET_HANDLER__";
4
4
  import manifest from "__STATIC_CONTENT_MANIFEST";
5
5
  const ASSET_MANIFEST = JSON.parse(manifest);
6
6
 
@@ -116943,7 +116943,7 @@ var yargs_default = Yargs;
116943
116943
 
116944
116944
  // package.json
116945
116945
  var name = "wrangler";
116946
- var version = "0.0.0-e5a3814";
116946
+ var version = "0.0.0-e61fba8";
116947
116947
  var author = "wrangler@cloudflare.com";
116948
116948
  var description = "Command-line interface for all things Cloudflare Workers";
116949
116949
  var bin = {
@@ -117057,6 +117057,7 @@ var files = [
117057
117057
  "templates",
117058
117058
  "vendor",
117059
117059
  "import_meta_url.js",
117060
+ "kv-asset-handler.js",
117060
117061
  "Cloudflare_CA.pem"
117061
117062
  ];
117062
117063
  var scripts = {
@@ -117242,6 +117243,21 @@ function parseJSON(input, file) {
117242
117243
  throw new ParseError({ text, location });
117243
117244
  }
117244
117245
  }
117246
+ function readFileSyncToBuffer(file) {
117247
+ try {
117248
+ return fs2.readFileSync(file);
117249
+ } catch (err2) {
117250
+ const { message } = err2;
117251
+ throw new ParseError({
117252
+ text: `Could not read file: ${file}`,
117253
+ notes: [
117254
+ {
117255
+ text: message.replace(file, (0, import_node_path5.resolve)(file))
117256
+ }
117257
+ ]
117258
+ });
117259
+ }
117260
+ }
117245
117261
  function readFileSync5(file) {
117246
117262
  try {
117247
117263
  return fs2.readFileSync(file, { encoding: "utf-8" });
@@ -118398,8 +118414,7 @@ Consider adding an environment configuration section to the wrangler.toml file:
118398
118414
  return { config, diagnostics };
118399
118415
  }
118400
118416
  function normalizeAndValidateBuild(diagnostics, rawEnv, rawBuild, configPath) {
118401
- const { command: command2, cwd: cwd2, watch_dir: _watch_dir, upload: upload2, ...rest } = rawBuild;
118402
- let { watch_dir } = rawBuild;
118417
+ const { command: command2, cwd: cwd2, watch_dir = "./src", upload: upload2, ...rest } = rawBuild;
118403
118418
  const deprecatedUpload = { ...upload2 };
118404
118419
  validateAdditionalProperties(diagnostics, "build", Object.keys(rest), []);
118405
118420
  validateOptionalProperty(diagnostics, "build", "command", command2, "string");
@@ -118422,7 +118437,6 @@ main = "${import_node_path7.default.join(rawBuild.upload?.dir ?? "./dist", rawBu
118422
118437
  \`\`\``, true);
118423
118438
  deprecated(diagnostics, rawEnv, "build.upload.dir", `Use the top level "main" field or a command-line argument to specify the entry-point for the Worker.`, true);
118424
118439
  }
118425
- watch_dir ||= "./src";
118426
118440
  return {
118427
118441
  command: command2,
118428
118442
  watch_dir: command2 && configPath ? Array.isArray(watch_dir) ? watch_dir.map((dir) => import_node_path7.default.relative(process.cwd(), import_node_path7.default.join(import_node_path7.default.dirname(configPath), `${dir}`))) : import_node_path7.default.relative(process.cwd(), import_node_path7.default.join(import_node_path7.default.dirname(configPath), `${watch_dir}`)) : watch_dir,
@@ -120513,9 +120527,6 @@ function useLocalWorker({
120513
120527
  timeout: 2e3,
120514
120528
  abortSignal: abortController.signal
120515
120529
  });
120516
- if (publicDirectory) {
120517
- throw new Error('\u2394 A "public" folder is not yet supported in local mode.');
120518
- }
120519
120530
  if (bindings.services && bindings.services.length > 0) {
120520
120531
  throw new Error("\u2394 Service bindings are not yet supported in local mode.");
120521
120532
  }
@@ -120605,9 +120616,12 @@ function useLocalWorker({
120605
120616
  local.current.stdout?.on("data", (data) => {
120606
120617
  process.stdout.write(data);
120607
120618
  });
120619
+ let stderrData = "";
120608
120620
  local.current.stderr?.on("data", (data) => {
120609
- const matches = /Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)/.exec(data.toString());
120621
+ stderrData += data.toString();
120622
+ const matches = /Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)[\r|\n]/.exec(stderrData);
120610
120623
  if (matches) {
120624
+ local.current?.stderr?.removeAllListeners("data");
120611
120625
  setInspectorUrl(matches[1]);
120612
120626
  }
120613
120627
  });
@@ -121114,6 +121128,7 @@ function Remote(props) {
121114
121128
  accountId: props.accountId,
121115
121129
  bindings: props.bindings,
121116
121130
  assetPaths: props.assetPaths,
121131
+ public: props.public,
121117
121132
  port: props.port,
121118
121133
  compatibilityDate: props.compatibilityDate,
121119
121134
  compatibilityFlags: props.compatibilityFlags,
@@ -121168,7 +121183,7 @@ function useWorker(props) {
121168
121183
  accountIdRef.current = await requireAuth({
121169
121184
  account_id: accountIdRef.current
121170
121185
  });
121171
- const assets = await syncAssets(accountIdRef.current, name2 + (!props.legacyEnv && props.env ? `-${props.env}` : ""), assetPaths, true, false);
121186
+ const assets = await syncAssets(accountIdRef.current, name2 + (!props.legacyEnv && props.env ? `-${props.env}` : ""), props.public ? void 0 : assetPaths, true, false);
121172
121187
  const content = await (0, import_promises4.readFile)(bundle.path, "utf-8");
121173
121188
  const init = {
121174
121189
  name: name2,
@@ -121231,6 +121246,7 @@ ${onboardingLink}`);
121231
121246
  accountId,
121232
121247
  port,
121233
121248
  assetPaths,
121249
+ props.public,
121234
121250
  compatibilityDate,
121235
121251
  compatibilityFlags,
121236
121252
  usageModel,
@@ -121338,7 +121354,7 @@ function getEntryPoint(entryFile, serveAssetsFromWorker) {
121338
121354
  if (serveAssetsFromWorker) {
121339
121355
  return {
121340
121356
  stdin: {
121341
- contents: fs4.readFileSync(path15.join(__dirname, "../templates/static-asset-facade.js"), "utf8").replace("__ENTRY_POINT__", entryFile),
121357
+ contents: fs4.readFileSync(path15.join(__dirname, "../templates/static-asset-facade.js"), "utf8").replace("__ENTRY_POINT__", entryFile.replaceAll("\\", "\\\\")).replace("__KV_ASSET_HANDLER__", path15.join(__dirname, "../kv-asset-handler.js").replaceAll("\\", "\\\\")),
121342
121358
  sourcefile: "static-asset-facade.js",
121343
121359
  resolveDir: path15.dirname(entryFile)
121344
121360
  }
@@ -121384,7 +121400,7 @@ function useEsbuild({
121384
121400
  if (!destination)
121385
121401
  return;
121386
121402
  const { resolvedEntryPointPath, bundleType, modules, stop } = await bundleWorker(entry, destination, {
121387
- serveAssetsFromWorker: false,
121403
+ serveAssetsFromWorker,
121388
121404
  jsxFactory,
121389
121405
  jsxFragment,
121390
121406
  rules,
@@ -121399,8 +121415,7 @@ function useEsbuild({
121399
121415
  entry,
121400
121416
  path: resolvedEntryPointPath,
121401
121417
  type: bundleType,
121402
- modules,
121403
- serveAssetsFromWorker
121418
+ modules
121404
121419
  });
121405
121420
  }
121406
121421
  build6().catch((err2) => {
@@ -121427,8 +121442,6 @@ function useEsbuild({
121427
121442
 
121428
121443
  // src/dev/dev.tsx
121429
121444
  function DevImplementation(props) {
121430
- const directory = useTmpDir();
121431
- useCustomBuild(props.entry, props.build);
121432
121445
  if (props.public && props.entry.format === "service-worker") {
121433
121446
  throw new Error("You cannot use the service-worker format with a `public` directory.");
121434
121447
  }
@@ -121441,25 +121454,11 @@ function DevImplementation(props) {
121441
121454
  if (props.bindings.data_blobs && props.entry.format === "modules") {
121442
121455
  throw new Error("You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml");
121443
121456
  }
121444
- const bundle = useEsbuild({
121445
- entry: props.entry,
121446
- destination: directory,
121447
- staticRoot: props.public,
121448
- jsxFactory: props.jsxFactory,
121449
- rules: props.rules,
121450
- jsxFragment: props.jsxFragment,
121451
- serveAssetsFromWorker: !!props.public,
121452
- tsconfig: props.tsconfig,
121453
- minify: props.minify,
121454
- nodeCompat: props.nodeCompat
121455
- });
121456
121457
  const { isRawModeSupported } = (0, import_ink3.useStdin)();
121457
121458
  return isRawModeSupported ? /* @__PURE__ */ import_react7.default.createElement(InteractiveDevSession, {
121458
- ...props,
121459
- bundle
121459
+ ...props
121460
121460
  }) : /* @__PURE__ */ import_react7.default.createElement(DevSession, {
121461
121461
  ...props,
121462
- bundle,
121463
121462
  local: props.initialMode === "local"
121464
121463
  });
121465
121464
  }
@@ -121489,9 +121488,23 @@ function InteractiveDevSession(props) {
121489
121488
  }, "[x]"), /* @__PURE__ */ import_react7.default.createElement(import_ink3.Text, null, " to exit")));
121490
121489
  }
121491
121490
  function DevSession(props) {
121491
+ useCustomBuild(props.entry, props.build);
121492
+ const directory = useTmpDir();
121493
+ const bundle = useEsbuild({
121494
+ entry: props.entry,
121495
+ destination: directory,
121496
+ staticRoot: props.public,
121497
+ jsxFactory: props.jsxFactory,
121498
+ rules: props.rules,
121499
+ jsxFragment: props.jsxFragment,
121500
+ serveAssetsFromWorker: !!props.public && !!props.local,
121501
+ tsconfig: props.tsconfig,
121502
+ minify: props.minify,
121503
+ nodeCompat: props.nodeCompat
121504
+ });
121492
121505
  return props.local ? /* @__PURE__ */ import_react7.default.createElement(Local, {
121493
121506
  name: props.name,
121494
- bundle: props.bundle,
121507
+ bundle,
121495
121508
  format: props.entry.format,
121496
121509
  compatibilityDate: props.compatibilityDate,
121497
121510
  localProtocol: props.localProtocol,
@@ -121507,7 +121520,7 @@ function DevSession(props) {
121507
121520
  crons: props.crons
121508
121521
  }) : /* @__PURE__ */ import_react7.default.createElement(Remote, {
121509
121522
  name: props.name,
121510
- bundle: props.bundle,
121523
+ bundle,
121511
121524
  format: props.entry.format,
121512
121525
  accountId: props.accountId,
121513
121526
  bindings: props.bindings,
@@ -124606,7 +124619,10 @@ async function publish(props) {
124606
124619
  available_on_subdomain = (await fetchResult(workerUrl, {
124607
124620
  method: "PUT",
124608
124621
  body: createWorkerUploadForm(worker)
124609
- }, new import_node_url12.URLSearchParams({ include_subdomain_availability: "true" }))).available_on_subdomain;
124622
+ }, new import_node_url12.URLSearchParams({
124623
+ include_subdomain_availability: "true",
124624
+ excludeScript: "true"
124625
+ }))).available_on_subdomain;
124610
124626
  }
124611
124627
  } finally {
124612
124628
  if (typeof destination !== "string") {
@@ -125579,6 +125595,9 @@ To start developing your Worker, run \`npx wrangler dev\`${isCreatingWranglerTom
125579
125595
  if (args["experimental-public"]) {
125580
125596
  logger.warn("The --experimental-public field is experimental and will change in the future.");
125581
125597
  }
125598
+ if (args["experimental-public"] && (args.site || config.site)) {
125599
+ throw new Error("Cannot use --experimental-public and a Site configuration together.");
125600
+ }
125582
125601
  if (args.public) {
125583
125602
  throw new Error("The --public field has been renamed to --experimental-public, and will change behaviour in the future.");
125584
125603
  }
@@ -125668,7 +125687,7 @@ To start developing your Worker, run \`npx wrangler dev\`${isCreatingWranglerTom
125668
125687
  localProtocol: args["local-protocol"] || config.dev.local_protocol,
125669
125688
  enableLocalPersistence: args["experimental-enable-local-persistence"] || false,
125670
125689
  accountId: config.account_id,
125671
- assetPaths: getAssetPaths(config, args.site, args.siteInclude, args.siteExclude),
125690
+ assetPaths: getAssetPaths(config, args["experimental-public"] || args.site, args.siteInclude, args.siteExclude),
125672
125691
  port: args.port || config.dev.port || await getLocalPort(),
125673
125692
  ip: args.ip || config.dev.ip,
125674
125693
  inspectorPort: args["inspector-port"] ?? await getInspectorPort(),
@@ -125780,15 +125799,18 @@ To start developing your Worker, run \`npx wrangler dev\`${isCreatingWranglerTom
125780
125799
  });
125781
125800
  }, async (args) => {
125782
125801
  await printWranglerBanner();
125802
+ const configPath = args.config || args.script && findWranglerToml(import_node_path21.default.dirname(args.script));
125803
+ const config = readConfig(configPath, args);
125804
+ const entry = await getEntry(args, config, "publish");
125783
125805
  if (args["experimental-public"]) {
125784
125806
  logger.warn("The --experimental-public field is experimental and will change in the future.");
125785
125807
  }
125808
+ if (args["experimental-public"] && (args.site || config.site)) {
125809
+ throw new Error("Cannot use --experimental-public and a Site configuration together.");
125810
+ }
125786
125811
  if (args.public) {
125787
125812
  throw new Error("The --public field has been renamed to --experimental-public, and will change behaviour in the future.");
125788
125813
  }
125789
- const configPath = args.config || args.script && findWranglerToml(import_node_path21.default.dirname(args.script));
125790
- const config = readConfig(configPath, args);
125791
- const entry = await getEntry(args, config, "publish");
125792
125814
  if (args.latest) {
125793
125815
  logger.warn("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");
125794
125816
  }
@@ -126294,7 +126316,7 @@ ${shouldDo}`);
126294
126316
  await printWranglerBanner();
126295
126317
  const config = readConfig(args.config, args);
126296
126318
  const namespaceId = getKVNamespaceId(args, config);
126297
- const value = args.path ? readFileSync5(args.path) : args.value;
126319
+ const value = args.path ? readFileSyncToBuffer(args.path) : args.value;
126298
126320
  if (args.path) {
126299
126321
  logger.log(`Writing the contents of ${args.path} to the key "${key2}" on namespace ${namespaceId}.`);
126300
126322
  } else {