wrangler 2.7.1 → 2.8.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.
Files changed (63) hide show
  1. package/package.json +1 -1
  2. package/src/__tests__/d1/d1.test.ts +12 -8
  3. package/src/__tests__/deployments.test.ts +4 -4
  4. package/src/__tests__/helpers/mock-dialogs.ts +2 -0
  5. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -5
  6. package/src/__tests__/helpers/mock-known-routes.ts +7 -2
  7. package/src/__tests__/helpers/mock-kv.ts +29 -16
  8. package/src/__tests__/helpers/mock-oauth-flow.ts +90 -98
  9. package/src/__tests__/helpers/msw/handlers/deployments.ts +20 -10
  10. package/src/__tests__/helpers/msw/handlers/namespaces.ts +18 -41
  11. package/src/__tests__/helpers/msw/handlers/r2.ts +14 -34
  12. package/src/__tests__/helpers/msw/handlers/script.ts +9 -28
  13. package/src/__tests__/helpers/msw/handlers/user.ts +13 -24
  14. package/src/__tests__/helpers/msw/handlers/zones.ts +6 -8
  15. package/src/__tests__/helpers/msw/index.ts +30 -1
  16. package/src/__tests__/init.test.ts +3 -14
  17. package/src/__tests__/jest.setup.ts +0 -23
  18. package/src/__tests__/pages-deployment-tail.test.ts +72 -1
  19. package/src/__tests__/pages.test.ts +52 -53
  20. package/src/__tests__/publish.test.ts +870 -522
  21. package/src/__tests__/r2.test.ts +11 -35
  22. package/src/__tests__/secret.test.ts +1 -9
  23. package/src/__tests__/tail.test.ts +72 -19
  24. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  25. package/src/__tests__/user.test.ts +5 -16
  26. package/src/__tests__/whoami.test.tsx +6 -17
  27. package/src/__tests__/worker-namespace.test.ts +56 -48
  28. package/src/api/index.ts +1 -0
  29. package/src/api/pages/index.ts +5 -0
  30. package/src/api/pages/publish.tsx +321 -0
  31. package/src/bundle.ts +62 -10
  32. package/src/cfetch/internal.ts +0 -3
  33. package/src/cli.ts +2 -2
  34. package/src/config/environment.ts +12 -10
  35. package/src/d1/backups.tsx +1 -5
  36. package/src/d1/utils.ts +1 -1
  37. package/src/deployments.ts +16 -6
  38. package/src/dev/local.tsx +1 -10
  39. package/src/dev/remote.tsx +2 -0
  40. package/src/dev/start-server.ts +5 -10
  41. package/src/dev/use-esbuild.ts +1 -0
  42. package/src/docs/index.ts +2 -1
  43. package/src/entry.ts +1 -2
  44. package/src/index.ts +1 -1
  45. package/src/init.ts +1 -1
  46. package/src/metrics/send-event.ts +2 -1
  47. package/src/pages/build.ts +4 -124
  48. package/src/pages/buildFunctions.ts +129 -0
  49. package/src/pages/dev.ts +68 -63
  50. package/src/pages/functions/buildPlugin.ts +3 -20
  51. package/src/pages/functions/buildWorker.ts +143 -21
  52. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  53. package/src/pages/publish.tsx +21 -220
  54. package/src/publish/publish.ts +30 -4
  55. package/src/tail/createTail.ts +28 -1
  56. package/src/tail/printing.ts +15 -0
  57. package/templates/checked-fetch.js +1 -3
  58. package/templates/d1-beta-facade.js +1 -1
  59. package/templates/middleware/loader-modules.ts +2 -0
  60. package/templates/tsconfig.tsbuildinfo +1 -1
  61. package/wrangler-dist/cli.d.ts +132 -10
  62. package/wrangler-dist/cli.js +3532 -3330
  63. package/src/__tests__/helpers/mock-cfetch.ts +0 -278
@@ -1,44 +1,31 @@
1
1
  import { rest } from "msw";
2
+ import { createFetchResult } from "../index";
2
3
 
3
4
  export const mswSuccessR2handlers = [
4
5
  // List endpoint r2Buckets
5
6
  rest.get("*/accounts/:accountId/r2/buckets", (_, response, context) =>
6
7
  response.once(
7
- context.status(200),
8
- context.json({
9
- success: true,
10
- errors: [],
11
- messages: [],
12
- result: {
8
+ context.json(
9
+ createFetchResult({
13
10
  buckets: [
14
11
  { name: "bucket-1", creation_date: "01-01-2001" },
15
12
  { name: "bucket-2", creation_date: "01-01-2001" },
16
13
  ],
17
- },
18
- })
14
+ })
15
+ )
19
16
  )
20
17
  ),
21
18
  rest.post("*/accounts/:accountId/r2/buckets", (_, response, context) =>
22
- response.once(
23
- context.status(200),
24
- context.json({ success: true, errors: [], messages: [], result: {} })
25
- )
19
+ response.once(context.json(createFetchResult({})))
26
20
  ),
27
21
  rest.put(
28
22
  "*/accounts/:accountId/r2/buckets/:bucketName",
29
- (_, response, context) =>
30
- response.once(
31
- context.status(200),
32
- context.json({ success: true, errors: [], messages: [], result: {} })
33
- )
23
+ (_, response, context) => response.once(context.json(createFetchResult({})))
34
24
  ),
35
25
  rest.delete(
36
26
  "*/accounts/:accountId/r2/buckets/:bucketName",
37
27
  (_, response, context) =>
38
- response.once(
39
- context.status(200),
40
- context.json({ success: true, errors: [], messages: [], result: null })
41
- )
28
+ response.once(context.json(createFetchResult(null)))
42
29
  ),
43
30
  rest.get(
44
31
  "*/accounts/:accountId/r2/buckets/:bucketName/objects/:objectName",
@@ -47,7 +34,7 @@ export const mswSuccessR2handlers = [
47
34
  return response.once(
48
35
  context.set("Content-Length", imageBuffer.byteLength.toString()),
49
36
  context.set("Content-Type", "image/png"),
50
- context.status(200),
37
+
51
38
  context.body(imageBuffer)
52
39
  );
53
40
  }
@@ -56,25 +43,18 @@ export const mswSuccessR2handlers = [
56
43
  "*/accounts/:accountId/r2/buckets/:bucketName/objects/:objectName",
57
44
  (_, response, context) =>
58
45
  response.once(
59
- context.status(200),
60
- context.json({
61
- success: true,
62
- errors: [],
63
- messages: [],
64
- result: {
46
+ context.json(
47
+ createFetchResult({
65
48
  accountId: "some-account-id",
66
49
  bucketName: "bucketName-object-test",
67
50
  objectName: "wormhole-img.png",
68
- },
69
- })
51
+ })
52
+ )
70
53
  )
71
54
  ),
72
55
  rest.delete(
73
56
  "*/accounts/:accountId/r2/buckets/:bucketName/objects/:objectName",
74
57
  (_, response, context) =>
75
- response.once(
76
- context.status(200),
77
- context.json({ success: true, errors: [], messages: [], result: null })
78
- )
58
+ response.once(context.json(createFetchResult(null)))
79
59
  ),
80
60
  ];
@@ -1,4 +1,5 @@
1
1
  import { rest } from "msw";
2
+ import { createFetchResult } from "../index";
2
3
  import type { WorkerMetadata } from "../../../../create-worker-upload-form";
3
4
 
4
5
  const bindings: Record<string, WorkerMetadata["bindings"]> = {
@@ -14,10 +15,12 @@ const scripts: Record<string, string> = {
14
15
  websocket: `new WebSocket("ws://dummy")`,
15
16
  response: `return new Response("ok")`,
16
17
  };
17
- function getBindings(scriptName: string) {
18
+ function getBindings(scriptName: string | readonly string[]) {
19
+ if (typeof scriptName !== "string") return "";
18
20
  return scriptName.split("--").flatMap((part) => bindings[part] ?? []);
19
21
  }
20
- function getScript(scriptName: string) {
22
+ function getScript(scriptName: string | readonly string[]): string {
23
+ if (typeof scriptName !== "string") return "";
21
24
  return `export default {fetch(request){
22
25
  ${scriptName
23
26
  .split("--")
@@ -29,47 +32,25 @@ export default [
29
32
  rest.get(
30
33
  "*/accounts/:accountId/workers/services/:scriptName/environments/:env/content",
31
34
  ({ params: { scriptName } }, res, context) => {
32
- return res(
33
- context.status(200),
34
- context.text(getScript(scriptName as string))
35
- );
35
+ return res(context.text(getScript(scriptName)));
36
36
  }
37
37
  ),
38
38
  rest.get(
39
39
  "*/accounts/:accountId/workers/scripts/:scriptName",
40
40
  ({ params: { scriptName } }, res, context) => {
41
- return res(
42
- context.status(200),
43
- context.text(getScript(scriptName as string))
44
- );
41
+ return res(context.text(getScript(scriptName)));
45
42
  }
46
43
  ),
47
44
  rest.get(
48
45
  "*/accounts/:accountId/workers/services/:scriptName/environments/:env/bindings",
49
46
  ({ params: { scriptName } }, res, context) => {
50
- return res(
51
- context.status(200),
52
- context.json({
53
- success: true,
54
- errors: [],
55
- messages: [],
56
- result: getBindings(scriptName as string),
57
- })
58
- );
47
+ return res(context.json(createFetchResult(getBindings(scriptName))));
59
48
  }
60
49
  ),
61
50
  rest.get(
62
51
  "*/accounts/:accountId/workers/scripts/:scriptName/bindings",
63
52
  ({ params: { scriptName } }, res, context) => {
64
- return res(
65
- context.status(200),
66
- context.json({
67
- success: true,
68
- errors: [],
69
- messages: [],
70
- result: getBindings(scriptName as string),
71
- })
72
- );
53
+ return res(context.json(createFetchResult(getBindings(scriptName))));
73
54
  }
74
55
  ),
75
56
  ];
@@ -1,14 +1,11 @@
1
1
  import { rest } from "msw";
2
+ import { createFetchResult } from "../index";
2
3
 
3
4
  export const mswSuccessUserHandlers = [
4
5
  rest.get("*/user", (_, response, cxt) => {
5
6
  return response.once(
6
- cxt.status(200),
7
- cxt.json({
8
- success: true,
9
- errors: [],
10
- messages: [],
11
- result: {
7
+ cxt.json(
8
+ createFetchResult({
12
9
  id: "7c5dae5552338874e5053f2534d2767a",
13
10
  email: "user@example.com",
14
11
  first_name: "John",
@@ -21,33 +18,25 @@ export const mswSuccessUserHandlers = [
21
18
  modified_on: "2014-01-01T05:20:00Z",
22
19
  two_factor_authentication_enabled: false,
23
20
  suspended: false,
24
- },
25
- })
21
+ })
22
+ )
26
23
  );
27
24
  }),
28
25
  rest.get("*/accounts", (_, response, cxt) => {
29
26
  return response.once(
30
- cxt.status(200),
31
- cxt.json({
32
- success: true,
33
- errors: [],
34
- messages: [],
35
- result: [
27
+ cxt.json(
28
+ createFetchResult([
36
29
  { name: "Account One", id: "account-1" },
37
30
  { name: "Account Two", id: "account-2" },
38
31
  { name: "Account Three", id: "account-3" },
39
- ],
40
- })
32
+ ])
33
+ )
41
34
  );
42
35
  }),
43
36
  rest.get("*/memberships", (_, response, context) => {
44
37
  return response.once(
45
- context.status(200),
46
- context.json({
47
- success: true,
48
- errors: [],
49
- messages: [],
50
- result: [
38
+ context.json(
39
+ createFetchResult([
51
40
  {
52
41
  id: "membership-id-1",
53
42
  account: { id: "account-id-1", name: "My Personal Account" },
@@ -56,8 +45,8 @@ export const mswSuccessUserHandlers = [
56
45
  id: "membership-id-2",
57
46
  account: { id: "account-id-2", name: "Enterprise Account" },
58
47
  },
59
- ],
60
- })
48
+ ])
49
+ )
61
50
  );
62
51
  }),
63
52
  ];
@@ -1,22 +1,20 @@
1
1
  import { rest } from "msw";
2
+ import { createFetchResult } from "../index";
2
3
 
3
4
  export default [
4
5
  rest.get("*/zones", ({ url: { searchParams } }, res, context) => {
5
6
  return res(
6
- context.status(200),
7
- context.json({
8
- success: true,
9
- errors: [],
10
- messages: [],
11
- result:
7
+ context.json(
8
+ createFetchResult(
12
9
  searchParams.get("name") === "exists.com"
13
10
  ? [
14
11
  {
15
12
  id: "exists-com",
16
13
  },
17
14
  ]
18
- : [],
19
- })
15
+ : []
16
+ )
17
+ )
20
18
  );
21
19
  }),
22
20
  ];
@@ -1,15 +1,43 @@
1
1
  import { setupServer } from "msw/node";
2
2
  import { default as mswAccessHandlers } from "./handlers/access";
3
- import { mswSuccessDeployments } from "./handlers/deployments";
3
+ import {
4
+ mswSuccessDeployments,
5
+ mswSuccessLastDeployment,
6
+ } from "./handlers/deployments";
4
7
  import { mswSuccessNamespacesHandlers } from "./handlers/namespaces";
5
8
  import { mswSuccessOauthHandlers } from "./handlers/oauth";
6
9
  import { mswSuccessR2handlers } from "./handlers/r2";
7
10
  import { default as mswSucessScriptHandlers } from "./handlers/script";
8
11
  import { mswSuccessUserHandlers } from "./handlers/user";
9
12
  import { default as mswZoneHandlers } from "./handlers/zones";
13
+
10
14
  export const msw = setupServer();
11
15
 
16
+ function createFetchResult(
17
+ result: unknown,
18
+ success = true,
19
+ errors: unknown[] = [],
20
+ messages: unknown[] = [],
21
+ result_info?: Record<string, unknown>
22
+ ) {
23
+ return result_info
24
+ ? {
25
+ result,
26
+ success,
27
+ errors,
28
+ messages,
29
+ result_info,
30
+ }
31
+ : {
32
+ result,
33
+ success,
34
+ errors,
35
+ messages,
36
+ };
37
+ }
38
+
12
39
  export {
40
+ createFetchResult,
13
41
  mswSuccessUserHandlers,
14
42
  mswSuccessR2handlers,
15
43
  mswSuccessOauthHandlers,
@@ -18,4 +46,5 @@ export {
18
46
  mswZoneHandlers,
19
47
  mswSuccessDeployments,
20
48
  mswAccessHandlers,
49
+ mswSuccessLastDeployment,
21
50
  };
@@ -4,9 +4,7 @@ import * as TOML from "@iarna/toml";
4
4
  import { execa, execaSync } from "execa";
5
5
  import { rest } from "msw";
6
6
  import { parseConfigFileTextToJson } from "typescript";
7
- import { FormData } from "undici";
8
7
  import { version as wranglerVersion } from "../../package.json";
9
- import { fetchDashboardScript } from "../cfetch/internal";
10
8
  import { getPackageManager } from "../package-manager";
11
9
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
12
10
  import { mockConsoleMethods } from "./helpers/mock-console";
@@ -46,8 +44,6 @@ describe("init", () => {
46
44
 
47
45
  afterEach(() => {
48
46
  clearDialogs();
49
- msw.resetHandlers();
50
- msw.restoreHandlers();
51
47
  });
52
48
 
53
49
  const std = mockConsoleMethods();
@@ -2798,6 +2794,7 @@ describe("init", () => {
2798
2794
  "isolinear-optical-chip/wrangler.toml": wranglerToml({
2799
2795
  ...mockConfigExpected,
2800
2796
  name: "isolinear-optical-chip",
2797
+ main: "src/index.js",
2801
2798
  }),
2802
2799
  },
2803
2800
  });
@@ -3070,19 +3067,11 @@ export function setMockFetchDashScript(mockResponse: string) {
3070
3067
  msw.use(
3071
3068
  rest.get(
3072
3069
  `*/accounts/:accountId/workers/services/:fromDashScriptName/environments/:environment/content`,
3073
- (req, res, ctx) => {
3074
- // This is a fake FormData object, until we can get MSW (beta) that supports FormData
3075
- const mockForm = new FormData();
3076
- mockForm.append("name", mockResponse);
3077
- // Sending it as JSON will result in empty object, but cause the fetchDashboardScript to execute its code
3078
- return res(ctx.status(200), ctx.json(mockForm));
3070
+ (_, res, ctx) => {
3071
+ return res(ctx.text(mockResponse));
3079
3072
  }
3080
3073
  )
3081
3074
  );
3082
- // Mock the actual return value that FormData would return
3083
- (fetchDashboardScript as jest.Mock).mockImplementationOnce(() => {
3084
- return mockResponse;
3085
- });
3086
3075
  }
3087
3076
 
3088
3077
  /**
@@ -1,16 +1,4 @@
1
1
  import fetchMock from "jest-fetch-mock";
2
- import {
3
- fetchDashboardScript,
4
- fetchInternal,
5
- fetchKVGetValue,
6
- fetchR2Objects,
7
- performApiFetch,
8
- } from "../cfetch/internal";
9
- import {
10
- mockFetchInternal,
11
- mockFetchR2Objects,
12
- mockPerformApiFetch,
13
- } from "./helpers/mock-cfetch";
14
2
  import { MockWebSocket } from "./helpers/mock-web-socket";
15
3
  import { msw } from "./helpers/msw";
16
4
 
@@ -89,17 +77,6 @@ afterEach(() => {
89
77
  });
90
78
  afterAll(() => msw.close());
91
79
 
92
- jest.mock("../cfetch/internal");
93
- (fetchDashboardScript as jest.Mock).mockImplementation(
94
- jest.requireActual("../cfetch/internal")["fetchDashboardScript"]
95
- );
96
- (fetchInternal as jest.Mock).mockImplementation(mockFetchInternal);
97
- (fetchKVGetValue as jest.Mock).mockImplementation(
98
- jest.requireActual("../cfetch/internal").fetchKVGetValue
99
- );
100
- (fetchR2Objects as jest.Mock).mockImplementation(mockFetchR2Objects);
101
- (performApiFetch as jest.Mock).mockImplementation(mockPerformApiFetch);
102
-
103
80
  jest.mock("../dev/dev", () => {
104
81
  const { useApp } = jest.requireActual("ink");
105
82
  const { useEffect } = jest.requireActual("react");
@@ -12,6 +12,7 @@ import type {
12
12
  RequestEvent,
13
13
  ScheduledEvent,
14
14
  AlarmEvent,
15
+ EmailEvent,
15
16
  } from "../tail/createTail";
16
17
  import type { RequestInit } from "undici";
17
18
  import type WebSocket from "ws";
@@ -355,6 +356,20 @@ describe("pages deployment tail", () => {
355
356
  expect(std.out).toMatch(deserializeToJson(serializedMessage));
356
357
  });
357
358
 
359
+ it("logs email messages in json format", async () => {
360
+ const api = mockTailAPIs();
361
+ await runWrangler(
362
+ "pages deployment tail mock-deployment-id --project-name mock-project --format json"
363
+ );
364
+
365
+ const event = generateMockEmailEvent();
366
+ const message = generateMockEventMessage({ event });
367
+ const serializedMessage = serialize(message);
368
+
369
+ api.ws.send(serializedMessage);
370
+ expect(std.out).toMatch(deserializeToJson(serializedMessage));
371
+ });
372
+
358
373
  it("logs request messages in pretty format", async () => {
359
374
  const api = mockTailAPIs();
360
375
  await runWrangler(
@@ -436,6 +451,33 @@ describe("pages deployment tail", () => {
436
451
  `);
437
452
  });
438
453
 
454
+ it("logs email messages in pretty format", async () => {
455
+ const api = mockTailAPIs();
456
+ await runWrangler(
457
+ "pages deployment tail mock-deployment-id --project-name mock-project --format pretty"
458
+ );
459
+
460
+ const event = generateMockEmailEvent();
461
+ const message = generateMockEventMessage({ event });
462
+ const serializedMessage = serialize(message);
463
+
464
+ api.ws.send(serializedMessage);
465
+ expect(
466
+ std.out
467
+ .replace(
468
+ new Date(mockEventTimestamp).toLocaleString(),
469
+ "[mock event timestamp]"
470
+ )
471
+ .replace(
472
+ mockTailExpiration.toLocaleString(),
473
+ "[mock expiration date]"
474
+ )
475
+ ).toMatchInlineSnapshot(`
476
+ "Connected to deployment mock-deployment-id, waiting for logs...
477
+ Email from:${mockEmailEventFrom} to:${mockEmailEventTo} size:${mockEmailEventSize} @ [mock event timestamp] - Ok"
478
+ `);
479
+ });
480
+
439
481
  it("should not crash when the tail message has a void event", async () => {
440
482
  const api = mockTailAPIs();
441
483
  await runWrangler(
@@ -608,7 +650,13 @@ function serialize(message: TailEventMessage): WebSocket.RawData {
608
650
  * @returns true if `event` is a RequestEvent
609
651
  */
610
652
  function isRequest(
611
- event: ScheduledEvent | RequestEvent | AlarmEvent | undefined | null
653
+ event:
654
+ | ScheduledEvent
655
+ | RequestEvent
656
+ | AlarmEvent
657
+ | EmailEvent
658
+ | undefined
659
+ | null
612
660
  ): event is RequestEvent {
613
661
  return Boolean(event && "request" in event);
614
662
  }
@@ -742,6 +790,21 @@ const mockEventTimestamp = 1645454470467;
742
790
  */
743
791
  const mockEventScheduledTime = new Date(mockEventTimestamp).toISOString();
744
792
 
793
+ /**
794
+ * Default value for email event from
795
+ */
796
+ const mockEmailEventFrom = "from@example.com";
797
+
798
+ /**
799
+ * Default value for email event to
800
+ */
801
+ const mockEmailEventTo = "to@example.com";
802
+
803
+ /**
804
+ * Default value for email event mail size
805
+ */
806
+ const mockEmailEventSize = 45416;
807
+
745
808
  /**
746
809
  * Mock out the API hit during Tail deletion
747
810
  *
@@ -882,3 +945,11 @@ function generateMockAlarmEvent(opts?: Partial<AlarmEvent>): AlarmEvent {
882
945
  scheduledTime: opts?.scheduledTime || mockEventScheduledTime,
883
946
  };
884
947
  }
948
+
949
+ function generateMockEmailEvent(opts?: Partial<EmailEvent>): EmailEvent {
950
+ return {
951
+ mailFrom: opts?.mailFrom || mockEmailEventFrom,
952
+ rcptTo: opts?.rcptTo || mockEmailEventTo,
953
+ rawSize: opts?.rawSize || mockEmailEventSize,
954
+ };
955
+ }