wrangler 0.0.0-e7a0cd5b → 0.0.0-e87ad068

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 (255) hide show
  1. package/README.md +3 -3
  2. package/bin/wrangler.js +30 -10
  3. package/miniflare-dist/index.mjs +254 -128
  4. package/package.json +27 -19
  5. package/src/__tests__/api-dev.test.ts +65 -36
  6. package/src/__tests__/api-devregistry.test.ts +121 -0
  7. package/src/__tests__/api.test.ts +27 -5
  8. package/src/__tests__/configuration.test.ts +797 -98
  9. package/src/__tests__/constellation.test.ts +371 -0
  10. package/src/__tests__/d1/d1.test.ts +82 -0
  11. package/src/__tests__/d1/execute.test.ts +66 -0
  12. package/src/__tests__/d1/migrate.test.ts +257 -0
  13. package/src/__tests__/d1/splitter.test.ts +255 -0
  14. package/src/__tests__/delete.test.ts +91 -49
  15. package/src/__tests__/deployments.test.ts +330 -56
  16. package/src/__tests__/dev.test.tsx +198 -90
  17. package/src/__tests__/generate.test.ts +12 -10
  18. package/src/__tests__/guess-worker-format.test.ts +35 -0
  19. package/src/__tests__/helpers/end-event-loop.ts +6 -0
  20. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  21. package/src/__tests__/helpers/mock-console.ts +6 -0
  22. package/src/__tests__/helpers/mock-dialogs.ts +71 -85
  23. package/src/__tests__/helpers/mock-get-pages-upload-token.ts +25 -0
  24. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -5
  25. package/src/__tests__/helpers/mock-known-routes.ts +7 -2
  26. package/src/__tests__/helpers/mock-kv.ts +29 -16
  27. package/src/__tests__/helpers/mock-oauth-flow.ts +103 -92
  28. package/src/__tests__/helpers/mock-process.ts +8 -13
  29. package/src/__tests__/helpers/mock-set-timeout.ts +16 -0
  30. package/src/__tests__/helpers/msw/blob-worker.cjs +19 -0
  31. package/src/__tests__/helpers/msw/handlers/deployments.ts +128 -27
  32. package/src/__tests__/helpers/msw/handlers/namespaces.ts +18 -41
  33. package/src/__tests__/helpers/msw/handlers/oauth.ts +13 -18
  34. package/src/__tests__/helpers/msw/handlers/r2.ts +14 -34
  35. package/src/__tests__/helpers/msw/handlers/script.ts +9 -28
  36. package/src/__tests__/helpers/msw/handlers/user.ts +13 -24
  37. package/src/__tests__/helpers/msw/handlers/zones.ts +6 -8
  38. package/src/__tests__/helpers/msw/index.ts +32 -1
  39. package/src/__tests__/helpers/msw/read-file-sync.js +61 -0
  40. package/src/__tests__/helpers/string-dynamic-values-matcher.ts +28 -0
  41. package/src/__tests__/helpers/worker-scripts/parent-worker.js +4 -1
  42. package/src/__tests__/index.test.ts +92 -72
  43. package/src/__tests__/init.test.ts +1033 -631
  44. package/src/__tests__/jest.setup.ts +19 -42
  45. package/src/__tests__/kv.test.ts +355 -231
  46. package/src/__tests__/logger.test.ts +68 -2
  47. package/src/__tests__/logout.test.ts +47 -0
  48. package/src/__tests__/metrics.test.ts +94 -51
  49. package/src/__tests__/middleware.scheduled.test.ts +42 -32
  50. package/src/__tests__/middleware.test.ts +212 -122
  51. package/src/__tests__/mtls-certificates.test.ts +589 -0
  52. package/src/__tests__/pages/deployment-list.test.ts +80 -0
  53. package/src/__tests__/pages/functions-build.test.ts +529 -0
  54. package/src/__tests__/pages/pages.test.ts +81 -0
  55. package/src/__tests__/pages/project-create.test.ts +63 -0
  56. package/src/__tests__/pages/project-list.test.ts +110 -0
  57. package/src/__tests__/pages/project-upload.test.ts +500 -0
  58. package/src/__tests__/pages/publish.test.ts +2864 -0
  59. package/src/__tests__/pages-deployment-tail.test.ts +957 -0
  60. package/src/__tests__/parse.test.ts +106 -0
  61. package/src/__tests__/publish.test.ts +2227 -1005
  62. package/src/__tests__/pubsub.test.ts +226 -100
  63. package/src/__tests__/queues.test.ts +238 -77
  64. package/src/__tests__/r2.test.ts +55 -57
  65. package/src/__tests__/secret.test.ts +179 -130
  66. package/src/__tests__/tail.test.ts +313 -113
  67. package/src/__tests__/test-old-node-version.js +3 -3
  68. package/src/__tests__/traverse-module-graph.test.ts +220 -0
  69. package/src/__tests__/tsconfig-sanity.ts +12 -0
  70. package/src/__tests__/tsconfig.json +8 -0
  71. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  72. package/src/__tests__/type-generation.test.ts +43 -26
  73. package/src/__tests__/unstableDev.test.ts +61 -0
  74. package/src/__tests__/user.test.ts +35 -72
  75. package/src/__tests__/whoami.test.tsx +8 -114
  76. package/src/__tests__/worker-namespace.test.ts +83 -69
  77. package/src/api/dev.ts +180 -60
  78. package/src/api/index.ts +10 -1
  79. package/src/api/mtls-certificate.ts +148 -0
  80. package/src/api/pages/create-worker-bundle-contents.ts +80 -0
  81. package/src/api/pages/index.ts +5 -0
  82. package/src/api/pages/publish.tsx +371 -0
  83. package/src/bundle.ts +315 -148
  84. package/src/cfetch/index.ts +0 -2
  85. package/src/cfetch/internal.ts +33 -33
  86. package/src/cli.ts +4 -4
  87. package/src/config/config.ts +14 -7
  88. package/src/config/environment.ts +120 -24
  89. package/src/config/index.ts +117 -35
  90. package/src/config/validation-helpers.ts +1 -1
  91. package/src/config/validation.ts +430 -19
  92. package/src/constellation/createProject.tsx +51 -0
  93. package/src/constellation/deleteProject.ts +51 -0
  94. package/src/constellation/deleteProjectModel.ts +76 -0
  95. package/src/constellation/index.ts +75 -0
  96. package/src/constellation/listCatalog.tsx +35 -0
  97. package/src/constellation/listModel.tsx +49 -0
  98. package/src/constellation/listProject.tsx +28 -0
  99. package/src/constellation/listRuntime.tsx +28 -0
  100. package/src/constellation/options.ts +17 -0
  101. package/src/constellation/types.ts +17 -0
  102. package/src/constellation/uploadModel.tsx +84 -0
  103. package/src/constellation/utils.ts +90 -0
  104. package/src/create-worker-preview.ts +19 -8
  105. package/src/create-worker-upload-form.ts +81 -18
  106. package/src/d1/backups.tsx +47 -46
  107. package/src/d1/constants.ts +5 -0
  108. package/src/d1/create.tsx +85 -37
  109. package/src/d1/{delete.tsx → delete.ts} +12 -15
  110. package/src/d1/execute.tsx +228 -156
  111. package/src/d1/index.ts +31 -7
  112. package/src/d1/list.tsx +27 -13
  113. package/src/d1/migrations/apply.tsx +235 -0
  114. package/src/d1/migrations/create.tsx +79 -0
  115. package/src/d1/migrations/helpers.ts +171 -0
  116. package/src/d1/migrations/index.ts +3 -0
  117. package/src/d1/migrations/list.tsx +95 -0
  118. package/src/d1/migrations/options.ts +23 -0
  119. package/src/d1/options.ts +12 -2
  120. package/src/d1/splitter.ts +161 -0
  121. package/src/d1/types.ts +32 -0
  122. package/src/d1/utils.ts +12 -2
  123. package/src/delete.ts +8 -16
  124. package/src/deployments.ts +340 -46
  125. package/src/deprecated/index.ts +8 -302
  126. package/src/dev/dev.tsx +66 -46
  127. package/src/dev/local.tsx +339 -104
  128. package/src/dev/remote.tsx +36 -3
  129. package/src/dev/start-server.ts +146 -101
  130. package/src/dev/use-esbuild.ts +82 -56
  131. package/src/dev/validate-dev-props.ts +9 -0
  132. package/src/{dev-registry.tsx → dev-registry.ts} +13 -1
  133. package/src/dev.tsx +202 -125
  134. package/src/dialogs.ts +136 -0
  135. package/src/dispatch-namespace.ts +21 -17
  136. package/src/docs/helpers.ts +50 -0
  137. package/src/docs/index.ts +54 -0
  138. package/src/entry.ts +26 -11
  139. package/src/environment-variables/factory.ts +89 -0
  140. package/src/environment-variables/misc-variables.ts +30 -0
  141. package/src/generate/index.ts +303 -0
  142. package/src/git-client.ts +15 -4
  143. package/src/{index.tsx → index.ts} +148 -63
  144. package/src/init.ts +301 -197
  145. package/src/inspect.ts +122 -6
  146. package/src/jest.d.ts +4 -0
  147. package/src/kv/helpers.ts +7 -4
  148. package/src/kv/index.ts +15 -17
  149. package/src/logger.ts +36 -5
  150. package/src/metrics/metrics-config.ts +3 -3
  151. package/src/metrics/send-event.ts +6 -1
  152. package/src/miniflare-cli/assets.ts +64 -28
  153. package/src/miniflare-cli/index.ts +6 -9
  154. package/src/miniflare-cli/tsconfig.json +9 -0
  155. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  156. package/src/miniflare-cli/types.ts +11 -0
  157. package/src/module-collection.ts +92 -26
  158. package/src/mtls-certificate/cli.ts +155 -0
  159. package/src/pages/build.ts +423 -0
  160. package/src/pages/buildFunctions.ts +140 -0
  161. package/src/pages/deployment-tails.ts +281 -0
  162. package/src/pages/deployments.tsx +11 -33
  163. package/src/pages/{dev.tsx → dev.ts} +192 -126
  164. package/src/pages/errors.ts +1 -0
  165. package/src/pages/functions/buildPlugin.ts +73 -69
  166. package/src/pages/functions/buildWorker.ts +342 -117
  167. package/src/pages/functions/tsconfig.json +8 -0
  168. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  169. package/src/pages/{functions.tsx → functions.ts} +8 -4
  170. package/src/pages/{index.tsx → index.ts} +11 -3
  171. package/src/pages/projects.tsx +12 -22
  172. package/src/pages/prompt-select-project.tsx +31 -0
  173. package/src/pages/publish.tsx +45 -214
  174. package/src/pages/types.ts +6 -9
  175. package/src/pages/upload.tsx +58 -14
  176. package/src/pages/utils.ts +14 -3
  177. package/src/parse.ts +23 -1
  178. package/src/paths.ts +1 -1
  179. package/src/proxy.ts +5 -0
  180. package/src/publish/index.ts +20 -16
  181. package/src/publish/publish.ts +81 -48
  182. package/src/pubsub/{pubsub-commands.tsx → pubsub-commands.ts} +19 -20
  183. package/src/queues/cli/commands/consumer/add.ts +24 -24
  184. package/src/queues/cli/commands/consumer/index.ts +3 -6
  185. package/src/queues/cli/commands/consumer/remove.ts +11 -18
  186. package/src/queues/cli/commands/create.ts +8 -8
  187. package/src/queues/cli/commands/delete.ts +8 -8
  188. package/src/queues/cli/commands/index.ts +6 -4
  189. package/src/queues/cli/commands/list.ts +8 -8
  190. package/src/queues/client.ts +1 -0
  191. package/src/queues/utils.ts +18 -0
  192. package/src/r2/constants.ts +4 -0
  193. package/src/r2/helpers.ts +1 -0
  194. package/src/r2/index.ts +40 -28
  195. package/src/secret/index.ts +18 -17
  196. package/src/{sites.tsx → sites.ts} +165 -53
  197. package/src/tail/createTail.ts +103 -3
  198. package/src/tail/filters.ts +1 -1
  199. package/src/tail/index.ts +8 -11
  200. package/src/tail/printing.ts +27 -0
  201. package/src/traverse-module-graph.ts +54 -0
  202. package/src/tsconfig-sanity.ts +16 -0
  203. package/src/type-generation.ts +85 -57
  204. package/src/user/access.ts +0 -1
  205. package/src/user/auth-variables.ts +113 -0
  206. package/src/user/choose-account.tsx +1 -31
  207. package/src/user/index.ts +0 -1
  208. package/src/user/{user.tsx → user.ts} +124 -82
  209. package/src/utils/render.ts +93 -0
  210. package/src/{whoami.tsx → whoami.ts} +37 -71
  211. package/src/worker.ts +61 -3
  212. package/src/yargs-types.ts +22 -5
  213. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  214. package/templates/__tests__/tsconfig.json +8 -0
  215. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  216. package/templates/checked-fetch.js +9 -3
  217. package/templates/d1-beta-facade.js +95 -25
  218. package/templates/facade.d.ts +14 -0
  219. package/templates/first-party-worker-module-facade.ts +4 -3
  220. package/templates/format-dev-errors.ts +8 -6
  221. package/templates/gitignore +1 -0
  222. package/templates/init-tests/test-jest-new-worker.js +3 -5
  223. package/templates/init-tests/test-vitest-new-worker.js +3 -5
  224. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  225. package/templates/middleware/loader-modules.ts +2 -2
  226. package/templates/middleware/loader-sw.ts +51 -31
  227. package/templates/middleware/middleware-miniflare3-json-error.ts +32 -0
  228. package/templates/new-worker.ts +3 -0
  229. package/templates/pages-dev-pipeline.ts +4 -1
  230. package/templates/pages-dev-util.ts +4 -1
  231. package/templates/pages-shim.ts +4 -1
  232. package/templates/pages-template-plugin.ts +19 -10
  233. package/templates/serve-static-assets.ts +17 -14
  234. package/templates/service-bindings-module-facade.js +1 -0
  235. package/templates/tsconfig-sanity.ts +11 -0
  236. package/templates/tsconfig.init.json +105 -0
  237. package/templates/tsconfig.json +5 -103
  238. package/templates/tsconfig.tsbuildinfo +1 -0
  239. package/wrangler-dist/cli.d.ts +902 -77
  240. package/wrangler-dist/cli.js +131685 -140615
  241. package/wrangler-dist/wasm-sync.wasm +0 -0
  242. package/src/__tests__/api-devregistry.test.js +0 -57
  243. package/src/__tests__/d1.test.ts +0 -72
  244. package/src/__tests__/dialogs.test.tsx +0 -40
  245. package/src/__tests__/helpers/mock-cfetch.ts +0 -333
  246. package/src/__tests__/pages.test.ts +0 -2223
  247. package/src/d1/types.tsx +0 -14
  248. package/src/dialogs.tsx +0 -163
  249. package/src/environment-variables.ts +0 -50
  250. package/src/pages/build.tsx +0 -238
  251. package/src/user/env-vars.ts +0 -46
  252. package/templates/experimental-local-cache-stubs.js +0 -27
  253. /package/src/{bundle-reporter.tsx → bundle-reporter.ts} +0 -0
  254. /package/src/dev/{get-local-persistence-path.tsx → get-local-persistence-path.ts} +0 -0
  255. /package/src/pages/{hash.tsx → hash.ts} +0 -0
@@ -1,12 +1,11 @@
1
1
  import MockWebSocket from "jest-websocket-mock";
2
+ import { rest } from "msw";
2
3
  import { Headers, Request } from "undici";
3
4
  import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
4
- import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
5
5
  import { mockConsoleMethods } from "./helpers/mock-console";
6
- import { mockGetZoneFromHostRequest } from "./helpers/mock-get-zone-from-host";
6
+ import { mockConfirm, clearDialogs } from "./helpers/mock-dialogs";
7
7
  import { useMockIsTTY } from "./helpers/mock-istty";
8
- import { mockCollectKnownRoutesRequest } from "./helpers/mock-known-routes";
9
- import { msw, mswSucessScriptHandlers } from "./helpers/msw";
8
+ import { createFetchResult, msw, mswSucessScriptHandlers } from "./helpers/msw";
10
9
  import { runInTempDir } from "./helpers/run-in-tmp";
11
10
  import { runWrangler } from "./helpers/run-wrangler";
12
11
  import type {
@@ -14,9 +13,12 @@ import type {
14
13
  RequestEvent,
15
14
  ScheduledEvent,
16
15
  AlarmEvent,
16
+ EmailEvent,
17
+ TailInfo,
17
18
  } from "../tail/createTail";
18
19
  import type { RequestInit } from "undici";
19
20
  import type WebSocket from "ws";
21
+
20
22
  describe("tail", () => {
21
23
  beforeEach(() => msw.use(...mswSucessScriptHandlers));
22
24
  runInTempDir();
@@ -28,7 +30,7 @@ describe("tail", () => {
28
30
  afterEach(() => {
29
31
  mockWebSockets.forEach((ws) => ws.close());
30
32
  mockWebSockets.splice(0);
31
- unsetAllMocks();
33
+ clearDialogs();
32
34
  });
33
35
 
34
36
  /**
@@ -46,15 +48,19 @@ describe("tail", () => {
46
48
  });
47
49
  it("warns about durable object restarts for tty", async () => {
48
50
  setIsTTY(true);
51
+ mockConfirm({
52
+ text: "Would you like to continue?",
53
+ result: false,
54
+ });
49
55
  const api = mockWebsocketAPIs();
50
56
  expect(api.requests.creation.length).toStrictEqual(0);
51
57
  await runWrangler("tail durable-object--websocket--response");
52
58
  expect(std.out).toMatchInlineSnapshot(`""`);
53
59
  expect(std.warn).toMatchInlineSnapshot(`
54
- "▲ [WARNING] Beginning log collection requires restarting the Durable Objects associated with durable-object--websocket--response. Any WebSocket connections or other non-persisted state will be lost as part of this restart.
60
+ "▲ [WARNING] Beginning log collection requires restarting the Durable Objects associated with durable-object--websocket--response. Any WebSocket connections or other non-persisted state will be lost as part of this restart.
55
61
 
56
- "
57
- `);
62
+ "
63
+ `);
58
64
  expect(std.err).toMatchInlineSnapshot(`""`);
59
65
  });
60
66
  it("creates and then delete tails", async () => {
@@ -67,38 +73,101 @@ describe("tail", () => {
67
73
  expect(api.requests.creation.length).toStrictEqual(1);
68
74
  expect(api.requests.deletion.count).toStrictEqual(0);
69
75
 
70
- api.ws.close();
76
+ await api.closeHelper();
71
77
  expect(api.requests.deletion.count).toStrictEqual(1);
72
78
  });
73
79
  it("should connect to the worker assigned to a given route", async () => {
74
80
  const api = mockWebsocketAPIs();
75
81
  expect(api.requests.creation.length).toStrictEqual(0);
76
82
 
77
- mockGetZoneFromHostRequest("example.com", "test-zone");
78
- mockCollectKnownRoutesRequest([
79
- {
80
- pattern: "example.com/*",
81
- script: "test-worker",
82
- },
83
- ]);
83
+ msw.use(
84
+ rest.get(`*/zones`, (req, res, ctx) => {
85
+ expect(req.url.searchParams.get("name")).toBe("example.com");
86
+ return res.once(
87
+ ctx.status(200),
88
+ ctx.json({
89
+ success: true,
90
+ errors: [],
91
+ messages: [],
92
+ result: [{ id: "test-zone" }],
93
+ })
94
+ );
95
+ })
96
+ );
97
+ msw.use(
98
+ rest.get(`*/zones/:zoneId/workers/routes`, (req, res, ctx) => {
99
+ return res.once(
100
+ ctx.status(200),
101
+ ctx.json({
102
+ success: true,
103
+ errors: [],
104
+ messages: [],
105
+ result: [
106
+ {
107
+ pattern: "example.com/*",
108
+ script: "test-worker",
109
+ },
110
+ ],
111
+ })
112
+ );
113
+ })
114
+ );
84
115
  await runWrangler("tail example.com/*");
85
116
 
86
117
  await expect(api.ws.connected).resolves.toBeTruthy();
87
118
  expect(api.requests.creation.length).toStrictEqual(1);
88
119
  expect(api.requests.deletion.count).toStrictEqual(0);
89
120
 
90
- api.ws.close();
121
+ await api.closeHelper();
91
122
  expect(api.requests.deletion.count).toStrictEqual(1);
92
123
  });
93
124
 
94
125
  it("should error if a given route is not assigned to the user's zone", async () => {
95
- mockGetZoneFromHostRequest("example.com", "test-zone");
96
- mockCollectKnownRoutesRequest([]);
126
+ msw.use(
127
+ rest.get(`*/zones`, (req, res, ctx) => {
128
+ expect(req.url.searchParams.get("name")).toBe("example.com");
129
+ return res.once(
130
+ ctx.status(200),
131
+ ctx.json({
132
+ success: true,
133
+ errors: [],
134
+ messages: [],
135
+ result: [{ id: "test-zone" }],
136
+ })
137
+ );
138
+ })
139
+ );
140
+ msw.use(
141
+ rest.get(`*/zones/:zoneId/workers/routes`, (req, res, ctx) => {
142
+ return res.once(
143
+ ctx.status(200),
144
+ ctx.json({
145
+ success: true,
146
+ errors: [],
147
+ messages: [],
148
+ result: [],
149
+ })
150
+ );
151
+ })
152
+ );
97
153
 
98
154
  await expect(runWrangler("tail example.com/*")).rejects.toThrow();
99
155
  });
100
156
  it("should error if a given route is not within the user's zone", async () => {
101
- mockGetZoneFromHostRequest("example.com");
157
+ msw.use(
158
+ rest.get(`*/zones`, (req, res, ctx) => {
159
+ expect(req.url.searchParams.get("name")).toBe("example.com");
160
+ return res.once(
161
+ ctx.status(200),
162
+ ctx.json({
163
+ success: true,
164
+ errors: [],
165
+ messages: [],
166
+ result: [],
167
+ })
168
+ );
169
+ })
170
+ );
102
171
 
103
172
  await expect(runWrangler("tail example.com/*")).rejects.toThrow();
104
173
  });
@@ -113,7 +182,7 @@ describe("tail", () => {
113
182
  expect(api.requests.creation.length).toStrictEqual(1);
114
183
  expect(api.requests.deletion.count).toStrictEqual(0);
115
184
 
116
- api.ws.close();
185
+ await api.closeHelper();
117
186
  expect(api.requests.deletion.count).toStrictEqual(1);
118
187
  });
119
188
 
@@ -127,13 +196,13 @@ describe("tail", () => {
127
196
  expect(api.requests.creation.length).toStrictEqual(1);
128
197
  expect(api.requests.deletion.count).toStrictEqual(0);
129
198
 
130
- api.ws.close();
199
+ await api.closeHelper();
131
200
  expect(api.requests.deletion.count).toStrictEqual(1);
132
201
  });
133
202
 
134
203
  it("errors when the websocket closes unexpectedly", async () => {
135
204
  const api = mockWebsocketAPIs();
136
- api.ws.close();
205
+ await api.closeHelper();
137
206
 
138
207
  await expect(runWrangler("tail test-worker")).rejects.toThrow();
139
208
  });
@@ -158,57 +227,72 @@ describe("tail", () => {
158
227
  await expect(tooLow).rejects.toThrow();
159
228
 
160
229
  await runWrangler("tail test-worker --sampling-rate 0.25");
161
- expect(api.requests.creation[0].body).toEqual(
162
- `{"filters":[{"sampling_rate":0.25}]}`
163
- );
230
+
231
+ expect(api.requests.creation[0]).toEqual({
232
+ filters: [{ sampling_rate: 0.25 }],
233
+ });
164
234
  });
165
235
 
166
236
  it("sends single status filters", async () => {
167
237
  const api = mockWebsocketAPIs();
168
238
  await runWrangler("tail test-worker --status error");
169
- expect(api.requests.creation[0].body).toEqual(
170
- `{"filters":[{"outcome":["exception","exceededCpu","exceededMemory","unknown"]}]}`
171
- );
239
+ expect(api.requests.creation[0]).toEqual({
240
+ filters: [
241
+ {
242
+ outcome: ["exception", "exceededCpu", "exceededMemory", "unknown"],
243
+ },
244
+ ],
245
+ });
172
246
  });
173
247
 
174
248
  it("sends multiple status filters", async () => {
175
249
  const api = mockWebsocketAPIs();
176
250
  await runWrangler("tail test-worker --status error --status canceled");
177
- expect(api.requests.creation[0].body).toEqual(
178
- `{"filters":[{"outcome":["exception","exceededCpu","exceededMemory","unknown","canceled"]}]}`
179
- );
251
+ expect(api.requests.creation[0]).toEqual({
252
+ filters: [
253
+ {
254
+ outcome: [
255
+ "exception",
256
+ "exceededCpu",
257
+ "exceededMemory",
258
+ "unknown",
259
+ "canceled",
260
+ ],
261
+ },
262
+ ],
263
+ });
180
264
  });
181
265
 
182
266
  it("sends single HTTP method filters", async () => {
183
267
  const api = mockWebsocketAPIs();
184
268
  await runWrangler("tail test-worker --method POST");
185
- expect(api.requests.creation[0].body).toEqual(
186
- `{"filters":[{"method":["POST"]}]}`
187
- );
269
+ expect(api.requests.creation[0]).toEqual({
270
+ filters: [{ method: ["POST"] }],
271
+ });
188
272
  });
189
273
 
190
274
  it("sends multiple HTTP method filters", async () => {
191
275
  const api = mockWebsocketAPIs();
192
276
  await runWrangler("tail test-worker --method POST --method GET");
193
- expect(api.requests.creation[0].body).toEqual(
194
- `{"filters":[{"method":["POST","GET"]}]}`
195
- );
277
+ expect(api.requests.creation[0]).toEqual({
278
+ filters: [{ method: ["POST", "GET"] }],
279
+ });
196
280
  });
197
281
 
198
282
  it("sends header filters without a query", async () => {
199
283
  const api = mockWebsocketAPIs();
200
284
  await runWrangler("tail test-worker --header X-CUSTOM-HEADER");
201
- expect(api.requests.creation[0].body).toEqual(
202
- `{"filters":[{"header":{"key":"X-CUSTOM-HEADER"}}]}`
203
- );
285
+ expect(api.requests.creation[0]).toEqual({
286
+ filters: [{ header: { key: "X-CUSTOM-HEADER" } }],
287
+ });
204
288
  });
205
289
 
206
290
  it("sends header filters with a query", async () => {
207
291
  const api = mockWebsocketAPIs();
208
292
  await runWrangler("tail test-worker --header X-CUSTOM-HEADER:some-value");
209
- expect(api.requests.creation[0].body).toEqual(
210
- `{"filters":[{"header":{"key":"X-CUSTOM-HEADER","query":"some-value"}}]}`
211
- );
293
+ expect(api.requests.creation[0]).toEqual({
294
+ filters: [{ header: { key: "X-CUSTOM-HEADER", query: "some-value" } }],
295
+ });
212
296
  });
213
297
 
214
298
  it("sends single IP filters", async () => {
@@ -216,9 +300,9 @@ describe("tail", () => {
216
300
  const fakeIp = "192.0.2.1";
217
301
 
218
302
  await runWrangler(`tail test-worker --ip ${fakeIp}`);
219
- expect(api.requests.creation[0].body).toEqual(
220
- `{"filters":[{"client_ip":["${fakeIp}"]}]}`
221
- );
303
+ expect(api.requests.creation[0]).toEqual({
304
+ filters: [{ client_ip: [fakeIp] }],
305
+ });
222
306
  });
223
307
 
224
308
  it("sends multiple IP filters", async () => {
@@ -226,9 +310,9 @@ describe("tail", () => {
226
310
  const fakeIp = "192.0.2.1";
227
311
 
228
312
  await runWrangler(`tail test-worker --ip ${fakeIp} --ip self`);
229
- expect(api.requests.creation[0].body).toEqual(
230
- `{"filters":[{"client_ip":["${fakeIp}","self"]}]}`
231
- );
313
+ expect(api.requests.creation[0]).toEqual({
314
+ filters: [{ client_ip: [fakeIp, "self"] }],
315
+ });
232
316
  });
233
317
 
234
318
  it("sends search filters", async () => {
@@ -236,9 +320,9 @@ describe("tail", () => {
236
320
  const search = "filterMe";
237
321
 
238
322
  await runWrangler(`tail test-worker --search ${search}`);
239
- expect(api.requests.creation[0].body).toEqual(
240
- `{"filters":[{"query":"${search}"}]}`
241
- );
323
+ expect(api.requests.creation[0]).toEqual({
324
+ filters: [{ query: search }],
325
+ });
242
326
  });
243
327
 
244
328
  it("sends everything but the kitchen sink", async () => {
@@ -259,10 +343,27 @@ describe("tail", () => {
259
343
  `--search ${query} ` +
260
344
  `--debug`;
261
345
 
262
- const expectedWebsocketMessage = `{"filters":[{"sampling_rate":0.69},{"outcome":["ok","exception","exceededCpu","exceededMemory","unknown"]},{"method":["GET","POST","PUT"]},{"header":{"key":"X-HELLO","query":"world"}},{"client_ip":["192.0.2.1","self"]},{"query":"onlyTheseMessagesPlease"}]}`;
346
+ const expectedWebsocketMessage = {
347
+ filters: [
348
+ { sampling_rate: 0.69 },
349
+ {
350
+ outcome: [
351
+ "ok",
352
+ "exception",
353
+ "exceededCpu",
354
+ "exceededMemory",
355
+ "unknown",
356
+ ],
357
+ },
358
+ { method: ["GET", "POST", "PUT"] },
359
+ { header: { key: "X-HELLO", query: "world" } },
360
+ { client_ip: ["192.0.2.1", "self"] },
361
+ { query: "onlyTheseMessagesPlease" },
362
+ ],
363
+ };
263
364
 
264
365
  await runWrangler(`tail test-worker ${cliFilters}`);
265
- expect(api.requests.creation[0].body).toEqual(expectedWebsocketMessage);
366
+ expect(api.requests.creation[0]).toEqual(expectedWebsocketMessage);
266
367
  });
267
368
  });
268
369
 
@@ -305,6 +406,18 @@ describe("tail", () => {
305
406
  expect(std.out).toMatch(deserializeToJson(serializedMessage));
306
407
  });
307
408
 
409
+ it("logs email messages in json format", async () => {
410
+ const api = mockWebsocketAPIs();
411
+ await runWrangler("tail test-worker --format json");
412
+
413
+ const event = generateMockEmailEvent();
414
+ const message = generateMockEventMessage({ event });
415
+ const serializedMessage = serialize(message);
416
+
417
+ api.ws.send(serializedMessage);
418
+ expect(std.out).toMatch(deserializeToJson(serializedMessage));
419
+ });
420
+
308
421
  it("logs request messages in pretty format", async () => {
309
422
  const api = mockWebsocketAPIs();
310
423
  await runWrangler("tail test-worker --format pretty");
@@ -320,10 +433,7 @@ describe("tail", () => {
320
433
  new Date(mockEventTimestamp).toLocaleString(),
321
434
  "[mock event timestamp]"
322
435
  )
323
- .replace(
324
- mockTailExpiration.toLocaleString(),
325
- "[mock expiration date]"
326
- )
436
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
327
437
  ).toMatchInlineSnapshot(`
328
438
  "Successfully created tail, expires at [mock expiration date]
329
439
  Connected to test-worker, waiting for logs...
@@ -346,10 +456,7 @@ describe("tail", () => {
346
456
  new Date(mockEventTimestamp).toLocaleString(),
347
457
  "[mock timestamp string]"
348
458
  )
349
- .replace(
350
- mockTailExpiration.toLocaleString(),
351
- "[mock expiration date]"
352
- )
459
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
353
460
  ).toMatchInlineSnapshot(`
354
461
  "Successfully created tail, expires at [mock expiration date]
355
462
  Connected to test-worker, waiting for logs...
@@ -372,10 +479,7 @@ describe("tail", () => {
372
479
  new Date(mockEventScheduledTime).toLocaleString(),
373
480
  "[mock scheduled time]"
374
481
  )
375
- .replace(
376
- mockTailExpiration.toLocaleString(),
377
- "[mock expiration date]"
378
- )
482
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
379
483
  ).toMatchInlineSnapshot(`
380
484
  "Successfully created tail, expires at [mock expiration date]
381
485
  Connected to test-worker, waiting for logs...
@@ -383,24 +487,70 @@ describe("tail", () => {
383
487
  `);
384
488
  });
385
489
 
386
- it("should not crash when the tail message has a void event", async () => {
490
+ it("logs email messages in pretty format", async () => {
387
491
  const api = mockWebsocketAPIs();
388
492
  await runWrangler("tail test-worker --format pretty");
389
493
 
390
- const message = generateMockEventMessage({ event: null });
494
+ const event = generateMockEmailEvent();
495
+ const message = generateMockEventMessage({ event });
391
496
  const serializedMessage = serialize(message);
392
497
 
393
498
  api.ws.send(serializedMessage);
394
499
  expect(
395
500
  std.out
396
501
  .replace(
397
- mockTailExpiration.toLocaleString(),
398
- "[mock expiration date]"
502
+ new Date(mockEventTimestamp).toLocaleString(),
503
+ "[mock event timestamp]"
399
504
  )
505
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
506
+ ).toMatchInlineSnapshot(`
507
+ "Successfully created tail, expires at [mock expiration date]
508
+ Connected to test-worker, waiting for logs...
509
+ Email from:from@example.com to:to@example.com size:45416 @ [mock event timestamp] - Ok"
510
+ `);
511
+ });
512
+
513
+ it("logs tail overload message", async () => {
514
+ const api = mockWebsocketAPIs();
515
+ await runWrangler("tail test-worker --format pretty");
516
+
517
+ let event = generateTailInfo(true);
518
+ let message = generateMockEventMessage({ event });
519
+ let serializedMessage = serialize(message);
520
+ api.ws.send(serializedMessage);
521
+
522
+ event = generateTailInfo(false);
523
+ message = generateMockEventMessage({ event });
524
+ serializedMessage = serialize(message);
525
+ api.ws.send(serializedMessage);
526
+ expect(
527
+ std.out.replace(
528
+ mockTailExpiration.toISOString(),
529
+ "[mock expiration date]"
530
+ )
531
+ ).toMatchInlineSnapshot(`
532
+ "Successfully created tail, expires at [mock expiration date]
533
+ Connected to test-worker, waiting for logs...
534
+ Tail is currently in sampling mode due to the high volume of messages. To prevent messages from being dropped consider adding filters.
535
+ Tail has exited sampling mode and is no longer dropping messages."
536
+ `);
537
+ });
538
+
539
+ it("should not crash when the tail message has a void event", async () => {
540
+ const api = mockWebsocketAPIs();
541
+ await runWrangler("tail test-worker --format pretty");
542
+
543
+ const message = generateMockEventMessage({ event: null });
544
+ const serializedMessage = serialize(message);
545
+
546
+ api.ws.send(serializedMessage);
547
+ expect(
548
+ std.out
400
549
  .replace(
401
550
  new Date(mockEventTimestamp).toLocaleString(),
402
551
  "[mock timestamp string]"
403
552
  )
553
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
404
554
  ).toMatchInlineSnapshot(`
405
555
  "Successfully created tail, expires at [mock expiration date]
406
556
  Connected to test-worker, waiting for logs...
@@ -424,10 +574,7 @@ describe("tail", () => {
424
574
  new Date(mockEventTimestamp).toLocaleString(),
425
575
  "[mock event timestamp]"
426
576
  )
427
- .replace(
428
- mockTailExpiration.toLocaleString(),
429
- "[mock expiration date]"
430
- )
577
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
431
578
  ).toMatchInlineSnapshot(`
432
579
  "Successfully created tail, expires at [mock expiration date]
433
580
  Connected to test-worker, waiting for logs...
@@ -480,10 +627,7 @@ describe("tail", () => {
480
627
  new Date(mockEventTimestamp).toLocaleString(),
481
628
  "[mock event timestamp]"
482
629
  )
483
- .replace(
484
- mockTailExpiration.toLocaleString(),
485
- "[mock expiration date]"
486
- )
630
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
487
631
  ).toMatchInlineSnapshot(`
488
632
  "Successfully created tail, expires at [mock expiration date]
489
633
  Connected to test-worker, waiting for logs...
@@ -553,7 +697,14 @@ function serialize(message: TailEventMessage): WebSocket.RawData {
553
697
  * @returns true if `event` is a RequestEvent
554
698
  */
555
699
  function isRequest(
556
- event: ScheduledEvent | RequestEvent | AlarmEvent | undefined | null
700
+ event:
701
+ | ScheduledEvent
702
+ | RequestEvent
703
+ | AlarmEvent
704
+ | EmailEvent
705
+ | TailInfo
706
+ | undefined
707
+ | null
557
708
  ): event is RequestEvent {
558
709
  return Boolean(event && "request" in event);
559
710
  }
@@ -581,6 +732,7 @@ type MockAPI = {
581
732
  };
582
733
  ws: MockWebSocket;
583
734
  nextMessageJson(): Promise<unknown>;
735
+ closeHelper: () => Promise<void>;
584
736
  };
585
737
 
586
738
  /**
@@ -607,22 +759,28 @@ function mockCreateTailRequest(
607
759
  const requests: RequestInit[] = [];
608
760
  const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
609
761
  const environment = env && !legacyEnv ? "/environments/:envName" : "";
610
- setMockResponse(
611
- `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails`,
612
- "POST",
613
- ([_url, accountId, scriptName, envName], req) => {
614
- requests.push(req);
615
- expect(accountId).toEqual("some-account-id");
616
- expect(scriptName).toEqual(expectedScriptName);
617
- if (!legacyEnv) {
618
- expect(envName).toEqual(env);
762
+ msw.use(
763
+ rest.post(
764
+ `*/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails`,
765
+ async (req, res, ctx) => {
766
+ const request = await req.json();
767
+ requests.push(request);
768
+ expect(req.params.accountId).toEqual("some-account-id");
769
+ expect(req.params.scriptName).toEqual(expectedScriptName);
770
+ if (!legacyEnv) {
771
+ expect(req.params.envName).toEqual(env);
772
+ }
773
+ return res.once(
774
+ ctx.json(
775
+ createFetchResult({
776
+ url: websocketURL,
777
+ id: "tail-id",
778
+ expires_at: mockTailExpiration,
779
+ })
780
+ )
781
+ );
619
782
  }
620
- return {
621
- id: "tail-id",
622
- url: websocketURL,
623
- expires_at: mockTailExpiration,
624
- };
625
- }
783
+ )
626
784
  );
627
785
 
628
786
  return requests;
@@ -643,6 +801,21 @@ const mockEventTimestamp = 1645454470467;
643
801
  */
644
802
  const mockEventScheduledTime = new Date(mockEventTimestamp).toISOString();
645
803
 
804
+ /**
805
+ * Default value for email event from
806
+ */
807
+ const mockEmailEventFrom = "from@example.com";
808
+
809
+ /**
810
+ * Default value for email event to
811
+ */
812
+ const mockEmailEventTo = "to@example.com";
813
+
814
+ /**
815
+ * Default value for email event mail size
816
+ */
817
+ const mockEmailEventSize = 45416;
818
+
646
819
  /**
647
820
  * Mock out the API hit during Tail deletion
648
821
  *
@@ -656,26 +829,22 @@ function mockDeleteTailRequest(
656
829
  const requests = { count: 0 };
657
830
  const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
658
831
  const environment = env && !legacyEnv ? "/environments/:envName" : "";
659
- setMockResponse(
660
- // "/accounts/:accountId/workers/scripts/:worker/tails",
661
- `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails/:tailId`,
662
- "DELETE",
663
- ([_url, accountId, scriptName, envNameOrTailId, tailId]) => {
664
- requests.count++;
665
- expect(accountId).toEqual("some-account-id");
666
- expect(scriptName).toEqual(expectedScriptName);
667
- if (!legacyEnv) {
668
- if (env) {
669
- expect(envNameOrTailId).toEqual(env);
670
- expect(tailId).toEqual("tail-id");
671
- } else {
672
- expect(envNameOrTailId).toEqual("tail-id");
832
+ msw.use(
833
+ rest.delete(
834
+ `*/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails/:tailId`,
835
+ async (req, res, ctx) => {
836
+ requests.count++;
837
+ expect(req.params.accountId).toEqual("some-account-id");
838
+ expect(req.params.scriptName).toEqual(expectedScriptName);
839
+ if (!legacyEnv) {
840
+ if (env) {
841
+ expect(req.params.tailId).toEqual("tail-id");
842
+ }
673
843
  }
674
- } else {
675
- expect(envNameOrTailId).toEqual("tail-id");
844
+ expect(req.params.tailId).toEqual("tail-id");
845
+ return res(ctx.json(createFetchResult(null)));
676
846
  }
677
- return null;
678
- }
847
+ )
679
848
  );
680
849
 
681
850
  return requests;
@@ -712,6 +881,15 @@ function mockWebsocketAPIs(
712
881
  const message = await api.ws.nextMessage;
713
882
  return JSON.parse(message as string);
714
883
  },
884
+ /**
885
+ * Close the mock websocket and clean up the API.
886
+ * The setTimeout forces a cycle to allow for closing and cleanup
887
+ * @returns a Promise that resolves when the websocket is closed
888
+ */
889
+ async closeHelper() {
890
+ api.ws.close();
891
+ await new Promise((resolve) => setTimeout(resolve, 0));
892
+ },
715
893
  };
716
894
  api.requests.creation = mockCreateTailRequest(
717
895
  websocketURL,
@@ -798,3 +976,25 @@ function generateMockAlarmEvent(opts?: Partial<AlarmEvent>): AlarmEvent {
798
976
  scheduledTime: opts?.scheduledTime || mockEventScheduledTime,
799
977
  };
800
978
  }
979
+
980
+ function generateMockEmailEvent(opts?: Partial<EmailEvent>): EmailEvent {
981
+ return {
982
+ mailFrom: opts?.mailFrom || mockEmailEventFrom,
983
+ rcptTo: opts?.rcptTo || mockEmailEventTo,
984
+ rawSize: opts?.rawSize || mockEmailEventSize,
985
+ };
986
+ }
987
+
988
+ function generateTailInfo(overload: boolean): TailInfo {
989
+ return overload
990
+ ? {
991
+ message:
992
+ "Tail is currently in sampling mode due to the high volume of messages. To prevent messages from being dropped consider adding filters.",
993
+ type: "overload",
994
+ }
995
+ : {
996
+ message:
997
+ "Tail has exited sampling mode and is no longer dropping messages.",
998
+ type: "overload-stop",
999
+ };
1000
+ }