wrangler 2.9.0 → 2.9.1

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.
@@ -669,7 +669,7 @@ async function generateHandler({
669
669
  return new HTMLRewriter().on("body", {
670
670
  element(e) {
671
671
  e.append(
672
- `<!-- Cloudflare Pages Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "${metadata.analytics?.token}"}'><\/script><!-- Cloudflare Pages Analytics -->`,
672
+ `<!-- Cloudflare Pages Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "${metadata.analytics?.token}"}'></script><!-- Cloudflare Pages Analytics -->`,
673
673
  { html: true }
674
674
  );
675
675
  }
@@ -6349,16 +6349,3 @@ async function main() {
6349
6349
  }
6350
6350
  }
6351
6351
  await main();
6352
- /**
6353
- * @fileoverview Main entrypoint for libraries using yargs-parser in Node.js
6354
- * CJS and ESM environments.
6355
- *
6356
- * @license
6357
- * Copyright (c) 2016, Contributors
6358
- * SPDX-License-Identifier: ISC
6359
- */
6360
- /**
6361
- * @license
6362
- * Copyright (c) 2016, Contributors
6363
- * SPDX-License-Identifier: ISC
6364
- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.9.0",
3
+ "version": "2.9.1",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -105,7 +105,7 @@
105
105
  "@miniflare/durable-objects": "2.11.0",
106
106
  "blake3-wasm": "^2.1.5",
107
107
  "chokidar": "^3.5.3",
108
- "esbuild": "0.14.51",
108
+ "esbuild": "0.16.3",
109
109
  "miniflare": "2.11.0",
110
110
  "nanoid": "^3.3.3",
111
111
  "path-to-regexp": "^6.2.0",
@@ -1,11 +1,8 @@
1
+ import { endEventLoop } from "../helpers/end-event-loop";
1
2
  import { mockConsoleMethods } from "../helpers/mock-console";
2
3
  import { runInTempDir } from "../helpers/run-in-tmp";
3
4
  import { runWrangler } from "../helpers/run-wrangler";
4
5
 
5
- function endEventLoop() {
6
- return new Promise((resolve) => setImmediate(resolve));
7
- }
8
-
9
6
  describe("d1", () => {
10
7
  const std = mockConsoleMethods();
11
8
  runInTempDir();
@@ -1,4 +1,6 @@
1
1
  import { cwd } from "process";
2
+ import { reinitialiseAuthTokens } from "../../user";
3
+ import { mockAccountId, mockApiToken } from "../helpers/mock-account-id";
2
4
  import { useMockIsTTY } from "../helpers/mock-istty";
3
5
  import { runInTempDir } from "../helpers/run-in-tmp";
4
6
  import { runWrangler } from "../helpers/run-wrangler";
@@ -8,6 +10,21 @@ describe("migrate", () => {
8
10
  runInTempDir();
9
11
  const { setIsTTY } = useMockIsTTY();
10
12
 
13
+ describe("create", () => {
14
+ it("should reject the --local flag for create", async () => {
15
+ setIsTTY(false);
16
+ writeWranglerToml({
17
+ d1_databases: [
18
+ { binding: "DATABASE", database_name: "db", database_id: "xxxx" },
19
+ ],
20
+ });
21
+
22
+ await expect(
23
+ runWrangler("d1 migrations create test some-message --local DATABASE")
24
+ ).rejects.toThrowError(`Unknown argument: local`);
25
+ });
26
+ });
27
+
11
28
  describe("apply", () => {
12
29
  it("should not attempt to login in local mode", async () => {
13
30
  setIsTTY(false);
@@ -45,4 +62,80 @@ describe("migrate", () => {
45
62
  );
46
63
  });
47
64
  });
65
+
66
+ describe("list", () => {
67
+ mockAccountId();
68
+ mockApiToken({ apiToken: null });
69
+
70
+ it("should not attempt to login in local mode", async () => {
71
+ setIsTTY(false);
72
+ writeWranglerToml({
73
+ d1_databases: [
74
+ { binding: "DATABASE", database_name: "db", database_id: "xxxx" },
75
+ ],
76
+ });
77
+ // If we get to the point where we are checking for migrations then we have not been asked to log in.
78
+ await expect(
79
+ runWrangler("d1 migrations list --local DATABASE")
80
+ ).rejects.toThrowError(
81
+ `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.`
82
+ );
83
+ });
84
+
85
+ it("should use the custom migrations folder when provided", async () => {
86
+ setIsTTY(false);
87
+ writeWranglerToml({
88
+ d1_databases: [
89
+ {
90
+ binding: "DATABASE",
91
+ database_name: "db",
92
+ database_id: "xxxx",
93
+ migrations_dir: "my-migrations-go-here",
94
+ },
95
+ ],
96
+ });
97
+ await expect(
98
+ runWrangler("d1 migrations list --local DATABASE")
99
+ ).rejects.toThrowError(
100
+ `No migrations present at ${cwd().replaceAll(
101
+ "\\",
102
+ "/"
103
+ )}/my-migrations-go-here.`
104
+ );
105
+ });
106
+
107
+ it("should try to read D1 config from wrangler.toml when logged in", async () => {
108
+ // no need to clear this env var as it's implicitly cleared by mockApiToken in afterEach
109
+ process.env.CLOUDFLARE_API_TOKEN = "api-token";
110
+ reinitialiseAuthTokens();
111
+ setIsTTY(false);
112
+ writeWranglerToml();
113
+ await expect(
114
+ runWrangler("d1 migrations list DATABASE")
115
+ ).rejects.toThrowError(
116
+ "Can't find a DB with name/binding 'DATABASE' in local config. Check info in wrangler.toml..."
117
+ );
118
+ });
119
+
120
+ it("should throw if user is not authenticated and not using --local", async () => {
121
+ setIsTTY(false);
122
+
123
+ await expect(
124
+ runWrangler("d1 migrations list DATABASE")
125
+ ).rejects.toThrowError(
126
+ "In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work"
127
+ );
128
+ });
129
+
130
+ it("should not try to read wrangler.toml in local mode", async () => {
131
+ setIsTTY(false);
132
+ writeWranglerToml();
133
+ // If we get to the point where we are checking for migrations then we have not checked wrangler.toml.
134
+ await expect(
135
+ runWrangler("d1 migrations list --local DATABASE")
136
+ ).rejects.toThrowError(
137
+ `No migrations present at ${cwd().replaceAll("\\", "/")}/migrations.`
138
+ );
139
+ });
140
+ });
48
141
  });
@@ -131,7 +131,7 @@ describe("generate", () => {
131
131
  // was harder than i thought, leaving this for now.
132
132
  it.todo("clones a cloudflare template with full checkouts");
133
133
 
134
- it("clones a user/repo template", async () => {
134
+ it.skip("clones a user/repo template", async () => {
135
135
  await expect(
136
136
  runWrangler("generate my-worker caass/wrangler-generate-test-template")
137
137
  ).resolves.toBeUndefined();
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Forces a tick and ensures that all pending promises resolve
3
+ */
4
+ export function endEventLoop() {
5
+ return new Promise((resolve) => setImmediate(resolve));
6
+ }
@@ -0,0 +1,25 @@
1
+ import { rest } from "msw";
2
+ import { msw } from "./msw";
3
+
4
+ /**
5
+ * Mocks the `/accounts/:accountId/pages/projects/:projectName/upload-token` GET request
6
+ */
7
+ export function mockGetUploadTokenRequest(
8
+ jwt: string,
9
+ accountId: string,
10
+ projectName: string
11
+ ) {
12
+ msw.use(
13
+ rest.get(
14
+ `*/accounts/:accountId/pages/projects/${projectName}/upload-token`,
15
+ (req, res, ctx) => {
16
+ expect(req.params.accountId).toEqual(accountId);
17
+
18
+ return res(
19
+ ctx.status(200),
20
+ ctx.json({ success: true, errors: [], messages: [], result: { jwt } })
21
+ );
22
+ }
23
+ )
24
+ );
25
+ }
@@ -0,0 +1,16 @@
1
+ let setTimeoutSpy: jest.SpyInstance;
2
+
3
+ export function mockSetTimeout() {
4
+ beforeEach(() => {
5
+ setTimeoutSpy = jest
6
+ .spyOn(global, "setTimeout")
7
+ // @ts-expect-error we're using a very simple setTimeout mock here
8
+ .mockImplementation((fn, _period) => {
9
+ setImmediate(fn);
10
+ });
11
+ });
12
+
13
+ afterEach(() => {
14
+ setTimeoutSpy.mockRestore();
15
+ });
16
+ }
@@ -1,4 +1,5 @@
1
1
  import { getPackageManager } from "../package-manager";
2
+ import { endEventLoop } from "./helpers/end-event-loop";
2
3
  import { mockConsoleMethods } from "./helpers/mock-console";
3
4
  import { runInTempDir } from "./helpers/run-in-tmp";
4
5
  import { runWrangler } from "./helpers/run-wrangler";
@@ -269,7 +270,3 @@ describe("wrangler", () => {
269
270
  `);
270
271
  });
271
272
  });
272
-
273
- function endEventLoop() {
274
- return new Promise((resolve) => setImmediate(resolve));
275
- }
@@ -1392,7 +1392,7 @@ describe("init", () => {
1392
1392
  contents: {
1393
1393
  config: {
1394
1394
  compilerOptions: expect.objectContaining({
1395
- types: ["@cloudflare/workers-types", "jest"],
1395
+ types: ["@cloudflare/workers-types", "vitest"],
1396
1396
  }),
1397
1397
  },
1398
1398
  error: undefined,
@@ -0,0 +1,78 @@
1
+ import { rest } from "msw";
2
+ import { endEventLoop } from "../helpers/end-event-loop";
3
+ import { mockAccountId, mockApiToken } from "./../helpers/mock-account-id";
4
+ import { msw } from "./../helpers/msw";
5
+ import { runInTempDir } from "./../helpers/run-in-tmp";
6
+ import { runWrangler } from "./../helpers/run-wrangler";
7
+ import type { Deployment } from "./../../pages/types";
8
+
9
+ describe("deployment list", () => {
10
+ runInTempDir();
11
+ mockAccountId();
12
+ mockApiToken();
13
+
14
+ afterEach(async () => {
15
+ // Force a tick to ensure that all promises resolve
16
+ await endEventLoop();
17
+ // Reset MSW after tick to ensure that all requests have been handled
18
+ msw.resetHandlers();
19
+ msw.restoreHandlers();
20
+ });
21
+
22
+ it("should make request to list deployments", async () => {
23
+ const deployments: Deployment[] = [
24
+ {
25
+ id: "87bbc8fe-16be-45cd-81e0-63d722e82cdf",
26
+ url: "https://87bbc8fe.images.pages.dev",
27
+ environment: "preview",
28
+ created_on: "2021-11-17T14:52:26.133835Z",
29
+ latest_stage: {
30
+ ended_on: "2021-11-17T14:52:26.133835Z",
31
+ status: "success",
32
+ },
33
+ deployment_trigger: {
34
+ metadata: {
35
+ branch: "main",
36
+ commit_hash: "c7649364c4cb32ad4f65b530b9424e8be5bec9d6",
37
+ },
38
+ },
39
+ project_name: "images",
40
+ },
41
+ ];
42
+
43
+ const requests = mockDeploymentListRequest(deployments);
44
+ await runWrangler("pages deployment list --project-name=images");
45
+
46
+ expect(requests.count).toBe(1);
47
+ });
48
+ });
49
+
50
+ /* -------------------------------------------------- */
51
+ /* Helper Functions */
52
+ /* -------------------------------------------------- */
53
+
54
+ function mockDeploymentListRequest(deployments: unknown[]) {
55
+ const requests = { count: 0 };
56
+ msw.use(
57
+ rest.get(
58
+ "*/accounts/:accountId/pages/projects/:project/deployments",
59
+ (req, res, ctx) => {
60
+ requests.count++;
61
+
62
+ expect(req.params.project).toEqual("images");
63
+ expect(req.params.accountId).toEqual("some-account-id");
64
+
65
+ return res.once(
66
+ ctx.status(200),
67
+ ctx.json({
68
+ success: true,
69
+ errors: [],
70
+ messages: [],
71
+ result: deployments,
72
+ })
73
+ );
74
+ }
75
+ )
76
+ );
77
+ return requests;
78
+ }
@@ -0,0 +1,81 @@
1
+ import { endEventLoop } from "../helpers/end-event-loop";
2
+ import { mockConsoleMethods } from "../helpers/mock-console";
3
+ import { runInTempDir } from "../helpers/run-in-tmp";
4
+ import { runWrangler } from "../helpers/run-wrangler";
5
+
6
+ describe("pages", () => {
7
+ const std = mockConsoleMethods();
8
+
9
+ runInTempDir();
10
+
11
+ afterEach(async () => {
12
+ // Force a tick to ensure that all promises resolve
13
+ await endEventLoop();
14
+ });
15
+
16
+ it("should display a list of available subcommands, for pages with no subcommand", async () => {
17
+ await runWrangler("pages");
18
+ await endEventLoop();
19
+
20
+ expect(std.out).toMatchInlineSnapshot(`
21
+ "wrangler pages
22
+
23
+ ⚡️ Configure Cloudflare Pages
24
+
25
+ Commands:
26
+ wrangler pages dev [directory] [-- command..] 🧑‍💻 Develop your full-stack Pages application locally
27
+ wrangler pages project ⚡️ Interact with your Pages projects
28
+ wrangler pages deployment 🚀 Interact with the deployments of a project
29
+ wrangler pages publish [directory] 🆙 Publish a directory of static assets as a Pages deployment
30
+
31
+ Flags:
32
+ -j, --experimental-json-config Experimental: Support wrangler.json [boolean]
33
+ -c, --config Path to .toml configuration file [string]
34
+ -e, --env Environment to use for operations and .env files [string]
35
+ -h, --help Show help [boolean]
36
+ -v, --version Show version number [boolean]
37
+
38
+ 🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose"
39
+ `);
40
+ });
41
+
42
+ describe("beta message for subcommands", () => {
43
+ it("should display for pages:dev", async () => {
44
+ await expect(
45
+ runWrangler("pages dev")
46
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
47
+ `"Must specify a directory of static assets to serve or a command to run or a proxy port."`
48
+ );
49
+
50
+ expect(std.out).toMatchInlineSnapshot(`
51
+ "🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
52
+
53
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
54
+ `);
55
+ });
56
+
57
+ it("should display for pages:functions:build", async () => {
58
+ await expect(runWrangler("pages functions build")).rejects.toThrowError();
59
+
60
+ expect(std.out).toMatchInlineSnapshot(`
61
+ "🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
62
+
63
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
64
+ `);
65
+ });
66
+
67
+ it("should display for pages:functions:optimize-routes", async () => {
68
+ await expect(
69
+ runWrangler(
70
+ 'pages functions optimize-routes --routes-path="/build/_routes.json" --output-routes-path="/build/_optimized-routes.json"'
71
+ )
72
+ ).rejects.toThrowError();
73
+
74
+ expect(std.out).toMatchInlineSnapshot(`
75
+ "🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/wrangler2/issues/new/choose
76
+
77
+ If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose"
78
+ `);
79
+ });
80
+ });
81
+ });
@@ -0,0 +1,63 @@
1
+ import { rest } from "msw";
2
+ import { endEventLoop } from "../helpers/end-event-loop";
3
+ import { mockAccountId, mockApiToken } from "./../helpers/mock-account-id";
4
+ import { mockConsoleMethods } from "./../helpers/mock-console";
5
+ import { msw } from "./../helpers/msw";
6
+ import { runInTempDir } from "./../helpers/run-in-tmp";
7
+ import { runWrangler } from "./../helpers/run-wrangler";
8
+
9
+ describe("project create", () => {
10
+ const std = mockConsoleMethods();
11
+
12
+ runInTempDir();
13
+ mockAccountId();
14
+ mockApiToken();
15
+
16
+ afterEach(async () => {
17
+ // Force a tick to ensure that all promises resolve
18
+ await endEventLoop();
19
+ // Reset MSW after tick to ensure that all requests have been handled
20
+ msw.resetHandlers();
21
+ msw.restoreHandlers();
22
+ });
23
+
24
+ it("should create a project with a production branch", async () => {
25
+ msw.use(
26
+ rest.post(
27
+ "*/accounts/:accountId/pages/projects",
28
+ async (req, res, ctx) => {
29
+ const body = await req.json();
30
+
31
+ expect(req.params.accountId).toEqual("some-account-id");
32
+ expect(body).toEqual({
33
+ name: "a-new-project",
34
+ production_branch: "main",
35
+ });
36
+
37
+ return res.once(
38
+ ctx.status(200),
39
+ ctx.json({
40
+ success: true,
41
+ errors: [],
42
+ messages: [],
43
+ result: {
44
+ name: "a-new-project",
45
+ subdomain: "a-new-project.pages.dev",
46
+ production_branch: "main",
47
+ },
48
+ })
49
+ );
50
+ }
51
+ )
52
+ );
53
+
54
+ await runWrangler(
55
+ "pages project create a-new-project --production-branch=main"
56
+ );
57
+
58
+ expect(std.out).toMatchInlineSnapshot(`
59
+ "✨ Successfully created the 'a-new-project' project. It will be available at https://a-new-project.pages.dev/ once you create your first deployment.
60
+ To deploy a folder of assets, run 'wrangler pages publish [directory]'."
61
+ `);
62
+ });
63
+ });
@@ -0,0 +1,108 @@
1
+ import { rest } from "msw";
2
+ import { endEventLoop } from "../helpers/end-event-loop";
3
+ import { mockAccountId, mockApiToken } from "./../helpers/mock-account-id";
4
+ import { msw } from "./../helpers/msw";
5
+ import { runInTempDir } from "./../helpers/run-in-tmp";
6
+ import { runWrangler } from "./../helpers/run-wrangler";
7
+ import type { Project } from "./../../pages/types";
8
+
9
+ describe("project list", () => {
10
+ runInTempDir();
11
+ mockAccountId();
12
+ mockApiToken();
13
+
14
+ afterEach(async () => {
15
+ // Force a tick to ensure that all promises resolve
16
+ await endEventLoop();
17
+ // Reset MSW after tick to ensure that all requests have been handled
18
+ msw.resetHandlers();
19
+ msw.restoreHandlers();
20
+ });
21
+
22
+ it("should make request to list projects", async () => {
23
+ const projects: Project[] = [
24
+ {
25
+ name: "dogs",
26
+ subdomain: "docs.pages.dev",
27
+ domains: ["dogs.pages.dev"],
28
+ source: {
29
+ type: "github",
30
+ },
31
+ latest_deployment: {
32
+ modified_on: "2021-11-17T14:52:26.133835Z",
33
+ },
34
+ created_on: "2021-11-17T14:52:26.133835Z",
35
+ production_branch: "main",
36
+ },
37
+ {
38
+ name: "cats",
39
+ subdomain: "cats.pages.dev",
40
+ domains: ["cats.pages.dev", "kitten.com"],
41
+ latest_deployment: {
42
+ modified_on: "2021-11-17T14:52:26.133835Z",
43
+ },
44
+ created_on: "2021-11-17T14:52:26.133835Z",
45
+ production_branch: "main",
46
+ },
47
+ ];
48
+
49
+ const requests = mockProjectListRequest(projects);
50
+ await runWrangler("pages project list");
51
+
52
+ expect(requests.count).toBe(1);
53
+ });
54
+
55
+ it("should make multiple requests for paginated results", async () => {
56
+ const projects: Project[] = [];
57
+ for (let i = 0; i < 15; i++) {
58
+ projects.push({
59
+ name: "dogs" + i,
60
+ subdomain: i + "dogs.pages.dev",
61
+ domains: [i + "dogs.pages.dev"],
62
+ source: {
63
+ type: "github",
64
+ },
65
+ latest_deployment: {
66
+ modified_on: "2021-11-17T14:52:26.133835Z",
67
+ },
68
+ created_on: "2021-11-17T14:52:26.133835Z",
69
+ production_branch: "main",
70
+ });
71
+ }
72
+ const requests = mockProjectListRequest(projects);
73
+ await runWrangler("pages project list");
74
+ expect(requests.count).toEqual(2);
75
+ });
76
+ });
77
+
78
+ /* -------------------------------------------------- */
79
+ /* Helper Functions */
80
+ /* -------------------------------------------------- */
81
+
82
+ function mockProjectListRequest(projects: unknown[]) {
83
+ const requests = { count: 0 };
84
+ msw.use(
85
+ rest.get("*/accounts/:accountId/pages/projects", async (req, res, ctx) => {
86
+ requests.count++;
87
+ const pageSize = Number(req.url.searchParams.get("per_page"));
88
+ const page = Number(req.url.searchParams.get("page"));
89
+ const expectedPageSize = 10;
90
+ const expectedPage = requests.count;
91
+ expect(req.params.accountId).toEqual("some-account-id");
92
+ expect(pageSize).toEqual(expectedPageSize);
93
+ expect(page).toEqual(expectedPage);
94
+ expect(await req.text()).toEqual("");
95
+
96
+ return res(
97
+ ctx.status(200),
98
+ ctx.json({
99
+ success: true,
100
+ errors: [],
101
+ messages: [],
102
+ result: projects.slice((page - 1) * pageSize, page * pageSize),
103
+ })
104
+ );
105
+ })
106
+ );
107
+ return requests;
108
+ }