wrangler 2.0.23 → 2.0.24

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 (55) hide show
  1. package/README.md +20 -2
  2. package/bin/wrangler.js +1 -1
  3. package/miniflare-dist/index.mjs +96 -34
  4. package/package.json +9 -4
  5. package/src/__tests__/configuration.test.ts +88 -16
  6. package/src/__tests__/dev.test.tsx +3 -0
  7. package/src/__tests__/generate.test.ts +93 -0
  8. package/src/__tests__/helpers/mock-cfetch.ts +54 -2
  9. package/src/__tests__/index.test.ts +10 -27
  10. package/src/__tests__/jest.setup.ts +31 -1
  11. package/src/__tests__/kv.test.ts +2 -2
  12. package/src/__tests__/metrics.test.ts +5 -0
  13. package/src/__tests__/publish.test.ts +497 -254
  14. package/src/__tests__/r2.test.ts +155 -71
  15. package/src/__tests__/user.test.ts +1 -0
  16. package/src/__tests__/validate-dev-props.test.ts +56 -0
  17. package/src/__tests__/whoami.test.tsx +60 -1
  18. package/src/bundle.ts +278 -44
  19. package/src/cfetch/internal.ts +34 -2
  20. package/src/config/config.ts +7 -2
  21. package/src/config/environment.ts +40 -8
  22. package/src/config/index.ts +13 -0
  23. package/src/config/validation.ts +101 -7
  24. package/src/create-worker-upload-form.ts +25 -0
  25. package/src/dev/dev.tsx +107 -28
  26. package/src/dev/local.tsx +20 -10
  27. package/src/dev/remote.tsx +39 -8
  28. package/src/dev/use-esbuild.ts +25 -0
  29. package/src/dev/validate-dev-props.ts +31 -0
  30. package/src/dev-registry.tsx +157 -0
  31. package/src/dev.tsx +93 -75
  32. package/src/generate.ts +112 -14
  33. package/src/index.tsx +182 -4
  34. package/src/inspect.ts +93 -5
  35. package/src/metrics/index.ts +1 -0
  36. package/src/metrics/metrics-dispatcher.ts +1 -0
  37. package/src/metrics/metrics-usage-headers.ts +24 -0
  38. package/src/metrics/send-event.ts +2 -2
  39. package/src/module-collection.ts +3 -3
  40. package/src/pages/constants.ts +1 -0
  41. package/src/pages/deployments.tsx +1 -1
  42. package/src/pages/dev.tsx +6 -1
  43. package/src/pages/publish.tsx +1 -1
  44. package/src/pages/upload.tsx +32 -13
  45. package/src/publish.ts +126 -112
  46. package/src/r2.ts +68 -0
  47. package/src/user/user.tsx +20 -2
  48. package/src/whoami.tsx +79 -1
  49. package/src/worker.ts +12 -0
  50. package/templates/first-party-worker-module-facade.ts +18 -0
  51. package/templates/format-dev-errors.ts +32 -0
  52. package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
  53. package/templates/service-bindings-module-facade.js +51 -0
  54. package/templates/service-bindings-sw-facade.js +39 -0
  55. package/wrangler-dist/cli.js +40192 -15265
@@ -0,0 +1,93 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import { setup } from "create-cloudflare";
5
+ import { mockConsoleMethods } from "./helpers/mock-console";
6
+ import { mockConfirm, clearConfirmMocks } from "./helpers/mock-dialogs";
7
+ import { runInTempDir } from "./helpers/run-in-tmp";
8
+ import { runWrangler } from "./helpers/run-wrangler";
9
+
10
+ const createCloudflareMock = setup as jest.Mock;
11
+
12
+ describe("generate", () => {
13
+ runInTempDir();
14
+ const std = mockConsoleMethods();
15
+
16
+ afterEach(() => {
17
+ clearConfirmMocks();
18
+ });
19
+
20
+ it("defers to `wrangler init` when no template is given", async () => {
21
+ mockConfirm(
22
+ {
23
+ text: "Would you like to use git to manage this Worker?",
24
+ result: false,
25
+ },
26
+ {
27
+ text: "No package.json found. Would you like to create one?",
28
+ result: false,
29
+ }
30
+ );
31
+ await runWrangler("generate no-template");
32
+ expect(std.out).toMatchInlineSnapshot(
33
+ `"✨ Created no-template/wrangler.toml"`
34
+ );
35
+ });
36
+
37
+ it("runs `create-cloudflare` when a template is given", async () => {
38
+ await expect(
39
+ runWrangler("generate my-worker some-template")
40
+ ).resolves.toBeUndefined();
41
+
42
+ expect(createCloudflareMock).toBeCalled();
43
+ });
44
+
45
+ it("complains when given the --type argument", async () => {
46
+ await expect(
47
+ runWrangler("generate worker-name worker-template --type rust")
48
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
49
+ `"The --type option is no longer supported."`
50
+ );
51
+ });
52
+
53
+ it("complains when given the --site argument", async () => {
54
+ await expect(runWrangler("generate worker-name worker-template --site"))
55
+ .rejects.toThrowErrorMatchingInlineSnapshot(`
56
+ "The --site option is no longer supported.
57
+ If you wish to create a brand new Worker Sites project then clone the \`worker-sites-template\` starter repository:
58
+
59
+ \`\`\`
60
+ git clone --depth=1 --branch=wrangler2 https://github.com/cloudflare/worker-sites-template worker-name
61
+ cd worker-name
62
+ \`\`\`
63
+
64
+ Find out more about how to create and maintain Sites projects at https://developers.cloudflare.com/workers/platform/sites.
65
+ Have you considered using Cloudflare Pages instead? See https://pages.cloudflare.com/."
66
+ `);
67
+ });
68
+
69
+ it("auto-increments the worker directory name", async () => {
70
+ fs.mkdirSync("my-worker");
71
+ await expect(
72
+ runWrangler("generate my-worker some-template")
73
+ ).resolves.toBeUndefined();
74
+
75
+ expect(createCloudflareMock).lastCalledWith(
76
+ path.resolve(process.cwd(), "my-worker-1"),
77
+ "some-template",
78
+ { debug: false, force: false, init: true }
79
+ );
80
+
81
+ fs.mkdirSync("my-worker-1");
82
+
83
+ await expect(
84
+ runWrangler("generate my-worker some-template")
85
+ ).resolves.toBeUndefined();
86
+
87
+ expect(createCloudflareMock).lastCalledWith(
88
+ path.resolve(process.cwd(), "my-worker-2"),
89
+ "some-template",
90
+ { debug: false, force: false, init: true }
91
+ );
92
+ });
93
+ });
@@ -1,8 +1,10 @@
1
+ import { Readable } from "node:stream";
1
2
  import { URL, URLSearchParams } from "node:url";
2
3
  import { pathToRegexp } from "path-to-regexp";
4
+ import { Response } from "undici";
3
5
  import { getCloudflareApiBaseUrl } from "../../cfetch";
4
6
  import type { FetchResult, FetchError } from "../../cfetch";
5
- import type { RequestInit } from "undici";
7
+ import type { RequestInit, BodyInit, HeadersInit } from "undici";
6
8
 
7
9
  /**
8
10
  * The signature of the function that will handle a mock request.
@@ -180,6 +182,7 @@ export function unsetAllMocks() {
180
182
  */
181
183
 
182
184
  const kvGetMocks = new Map<string, string | Buffer>();
185
+ const r2GetMocks = new Map<string, string | undefined>();
183
186
 
184
187
  /**
185
188
  * @mocked typeof fetchKVGetValue
@@ -206,6 +209,55 @@ export function setMockFetchKVGetValue(
206
209
  kvGetMocks.set(`${accountId}/${namespaceId}/${key}`, value);
207
210
  }
208
211
 
209
- export function unsetMockFetchKVGetValues() {
212
+ /**
213
+ * @mocked typeof fetchR2Objects
214
+ */
215
+ export async function mockFetchR2Objects(
216
+ resource: string,
217
+ bodyInit: {
218
+ body: BodyInit | Readable;
219
+ headers: HeadersInit | undefined;
220
+ method: "PUT" | "GET";
221
+ }
222
+ ): Promise<Response> {
223
+ /**
224
+ * Here we destroy & removeListeners to "drain" the stream, for testing purposes
225
+ * mimicking the fetch request taking in the stream and draining it.
226
+ */
227
+ if (bodyInit.body instanceof Readable) {
228
+ bodyInit.body.destroy();
229
+ bodyInit.body.removeAllListeners();
230
+ }
231
+
232
+ if (r2GetMocks.has(resource)) {
233
+ const value = r2GetMocks.get(resource);
234
+
235
+ return new Response(value);
236
+ }
237
+ throw new Error(`no expected mock found for \`r2 object get\` - ${resource}`);
238
+ }
239
+
240
+ /**
241
+ * Mock setter for usage within test blocks, companion helper to `mockFetchR2Objects`
242
+ */
243
+ export function setMockFetchR2Objects({
244
+ accountId,
245
+ bucketName,
246
+ objectName,
247
+ mockResponse,
248
+ }: {
249
+ accountId: string;
250
+ bucketName: string;
251
+ objectName: string;
252
+ mockResponse?: string;
253
+ }) {
254
+ r2GetMocks.set(
255
+ `/accounts/${accountId}/r2/buckets/${bucketName}/objects/${objectName}`,
256
+ mockResponse
257
+ );
258
+ }
259
+
260
+ export function unsetSpecialMockFns() {
210
261
  kvGetMocks.clear();
262
+ r2GetMocks.clear();
211
263
  }
@@ -203,36 +203,19 @@ describe("wrangler", () => {
203
203
  await runWrangler("r2");
204
204
  await endEventLoop();
205
205
  expect(std.out).toMatchInlineSnapshot(`
206
- "wrangler r2
206
+ "wrangler r2
207
207
 
208
- 📦 Interact with an R2 store
208
+ 📦 Interact with an R2 store
209
209
 
210
- Commands:
211
- wrangler r2 bucket Manage R2 buckets
212
-
213
- Flags:
214
- -c, --config Path to .toml configuration file [string]
215
- -h, --help Show help [boolean]
216
- -v, --version Show version number [boolean]"
217
- `);
218
- });
219
- });
210
+ Commands:
211
+ wrangler r2 object Manage R2 objects
212
+ wrangler r2 bucket Manage R2 buckets
220
213
 
221
- describe("Deprecated commands", () => {
222
- it("should print a deprecation message for 'generate'", async () => {
223
- await runWrangler("generate").catch((err) => {
224
- expect(err.message).toMatchInlineSnapshot(`
225
- "Deprecation:
226
- \`wrangler generate\` has been deprecated.
227
- Try running \`wrangler init\` to generate a basic Worker, or cloning the template repository instead:
228
-
229
- \`\`\`
230
- git clone https://github.com/cloudflare/worker-template
231
- \`\`\`
232
-
233
- Please refer to https://developers.cloudflare.com/workers/wrangler/deprecations/#generate for more information."
234
- `);
235
- });
214
+ Flags:
215
+ -c, --config Path to .toml configuration file [string]
216
+ -h, --help Show help [boolean]
217
+ -v, --version Show version number [boolean]"
218
+ `);
236
219
  });
237
220
  });
238
221
 
@@ -2,10 +2,15 @@ import fetchMock from "jest-fetch-mock";
2
2
  import {
3
3
  fetchInternal,
4
4
  fetchKVGetValue,
5
+ fetchR2Objects,
5
6
  getCloudflareAPIBaseURL,
6
7
  } from "../cfetch/internal";
7
8
  import { confirm, prompt } from "../dialogs";
8
- import { mockFetchInternal, mockFetchKVGetValue } from "./helpers/mock-cfetch";
9
+ import {
10
+ mockFetchInternal,
11
+ mockFetchKVGetValue,
12
+ mockFetchR2Objects,
13
+ } from "./helpers/mock-cfetch";
9
14
  import { MockWebSocket } from "./helpers/mock-web-socket";
10
15
 
11
16
  // Mock out getPort since we don't actually care about what ports are open in unit tests.
@@ -43,6 +48,7 @@ jest.mock("../cfetch/internal");
43
48
  (getCloudflareAPIBaseURL as jest.Mock).mockReturnValue(
44
49
  "https://api.cloudflare.com/client/v4"
45
50
  );
51
+ (fetchR2Objects as jest.Mock).mockImplementation(mockFetchR2Objects);
46
52
 
47
53
  jest.mock("../dialogs");
48
54
 
@@ -118,3 +124,27 @@ jest.mock("xdg-app-paths", () => {
118
124
  }),
119
125
  };
120
126
  });
127
+
128
+ jest.mock("create-cloudflare");
129
+
130
+ jest.mock("../metrics/metrics-config", () => {
131
+ const realModule = jest.requireActual("../metrics/metrics-config");
132
+ const fakeModule = {
133
+ ...realModule,
134
+ // Although we mock out the getMetricsConfig() function in most tests,
135
+ // we need a way to reinstate it for the metrics specific tests.
136
+ // This is what `useOriginal` is for.
137
+ useOriginal: false,
138
+ getMetricsConfig: (...args: unknown[]) =>
139
+ fakeModule.useOriginal
140
+ ? realModule.getMetricsConfig(...args)
141
+ : async () => {
142
+ return {
143
+ enabled: false,
144
+ deviceId: "mock-device",
145
+ userId: undefined,
146
+ };
147
+ },
148
+ };
149
+ return fakeModule;
150
+ });
@@ -4,7 +4,7 @@ import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
4
4
  import {
5
5
  setMockResponse,
6
6
  unsetAllMocks,
7
- unsetMockFetchKVGetValues,
7
+ unsetSpecialMockFns,
8
8
  setMockFetchKVGetValue,
9
9
  setMockRawResponse,
10
10
  createFetchResult,
@@ -924,7 +924,7 @@ describe("wrangler", () => {
924
924
 
925
925
  describe("get", () => {
926
926
  afterEach(() => {
927
- unsetMockFetchKVGetValues();
927
+ unsetSpecialMockFns();
928
928
  });
929
929
 
930
930
  it("should get a key in a given namespace specified by namespace-id", async () => {
@@ -26,6 +26,9 @@ describe("metrics", () => {
26
26
  runInTempDir();
27
27
 
28
28
  beforeEach(() => {
29
+ // Tell jest to use the original version of the `getMetricsConfig()` function in these tests.
30
+ const mockMetricsConfig = jest.requireMock("../metrics/metrics-config");
31
+ mockMetricsConfig.useOriginal = true;
29
32
  global.SPARROW_SOURCE_KEY = "MOCK_KEY";
30
33
  logger.loggerLevel = "debug";
31
34
  // Create a node_modules directory to store config-cache files
@@ -65,6 +68,7 @@ describe("metrics", () => {
65
68
  properties: {
66
69
  category: "Workers",
67
70
  wranglerVersion,
71
+ os: process.platform + ":" + process.arch,
68
72
  a: 1,
69
73
  b: 2,
70
74
  },
@@ -139,6 +143,7 @@ describe("metrics", () => {
139
143
  properties: {
140
144
  category: "Workers",
141
145
  wranglerVersion,
146
+ os: process.platform + ":" + process.arch,
142
147
  a: 1,
143
148
  b: 2,
144
149
  },