wrangler 0.0.0-e178d6fb → 0.0.0-e1c2f5b9

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 (239) hide show
  1. package/README.md +16 -2
  2. package/bin/wrangler.js +31 -11
  3. package/miniflare-dist/index.mjs +1340 -330
  4. package/package.json +40 -13
  5. package/src/__tests__/access.test.ts +25 -0
  6. package/src/__tests__/api-dev.test.ts +238 -0
  7. package/src/__tests__/api-devregistry.test.js +64 -0
  8. package/src/__tests__/api.test.ts +80 -0
  9. package/src/__tests__/configuration.test.ts +683 -470
  10. package/src/__tests__/d1.test.ts +123 -0
  11. package/src/__tests__/delete.test.ts +263 -0
  12. package/src/__tests__/deployments.test.ts +105 -0
  13. package/src/__tests__/dev.test.tsx +453 -70
  14. package/src/__tests__/dialogs.test.tsx +40 -0
  15. package/src/__tests__/generate.test.ts +235 -0
  16. package/src/__tests__/get-host-from-url.test.ts +16 -0
  17. package/src/__tests__/helpers/mock-auth-domain.ts +20 -0
  18. package/src/__tests__/helpers/mock-cfetch.ts +92 -26
  19. package/src/__tests__/helpers/mock-console.ts +11 -2
  20. package/src/__tests__/helpers/mock-dialogs.ts +1 -1
  21. package/src/__tests__/helpers/mock-get-zone-from-host.ts +8 -0
  22. package/src/__tests__/helpers/mock-known-routes.ts +7 -0
  23. package/src/__tests__/helpers/mock-kv.ts +1 -1
  24. package/src/__tests__/helpers/mock-oauth-flow.ts +74 -53
  25. package/src/__tests__/helpers/mock-process.ts +8 -13
  26. package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
  27. package/src/__tests__/helpers/msw/handlers/deployments.ts +59 -0
  28. package/src/__tests__/helpers/msw/handlers/namespaces.ts +104 -0
  29. package/src/__tests__/helpers/msw/handlers/oauth.ts +31 -0
  30. package/src/__tests__/helpers/msw/handlers/r2.ts +80 -0
  31. package/src/__tests__/helpers/msw/handlers/script.ts +75 -0
  32. package/src/__tests__/helpers/msw/handlers/user.ts +63 -0
  33. package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
  34. package/src/__tests__/helpers/msw/index.ts +21 -0
  35. package/src/__tests__/helpers/worker-scripts/child-wrangler.toml +1 -0
  36. package/src/__tests__/helpers/worker-scripts/hello-world-worker.js +5 -0
  37. package/src/__tests__/helpers/worker-scripts/hello-world-wrangler.toml +1 -0
  38. package/src/__tests__/helpers/worker-scripts/parent-worker.js +8 -0
  39. package/src/__tests__/helpers/worker-scripts/parent-wrangler.toml +5 -0
  40. package/src/__tests__/index.test.ts +103 -97
  41. package/src/__tests__/init.test.ts +1484 -382
  42. package/src/__tests__/jest.setup.ts +88 -5
  43. package/src/__tests__/kv.test.ts +655 -540
  44. package/src/__tests__/logout.test.ts +47 -0
  45. package/src/__tests__/metrics.test.ts +95 -45
  46. package/src/__tests__/middleware.scheduled.test.ts +145 -0
  47. package/src/__tests__/middleware.test.ts +750 -0
  48. package/src/__tests__/pages-deployment-tail.test.ts +884 -0
  49. package/src/__tests__/pages.test.ts +1301 -119
  50. package/src/__tests__/paths.test.ts +39 -0
  51. package/src/__tests__/publish.test.ts +2266 -1180
  52. package/src/__tests__/pubsub.test.ts +211 -88
  53. package/src/__tests__/queues.test.ts +522 -0
  54. package/src/__tests__/r2.test.ts +363 -203
  55. package/src/__tests__/secret.test.ts +261 -59
  56. package/src/__tests__/tail.test.ts +352 -151
  57. package/src/__tests__/test-old-node-version.js +3 -3
  58. package/src/__tests__/tsconfig-sanity.ts +12 -0
  59. package/src/__tests__/tsconfig.json +8 -0
  60. package/src/__tests__/tsconfig.tsbuildinfo +1 -0
  61. package/src/__tests__/type-generation.test.ts +233 -0
  62. package/src/__tests__/user.test.ts +59 -73
  63. package/src/__tests__/utils-collectKeyValues.test.ts +47 -0
  64. package/src/__tests__/validate-dev-props.test.ts +56 -0
  65. package/src/__tests__/whoami.test.tsx +114 -66
  66. package/src/__tests__/worker-namespace.test.ts +154 -155
  67. package/src/api/dev.ts +170 -38
  68. package/src/api/index.ts +1 -0
  69. package/src/bundle-reporter.tsx +41 -2
  70. package/src/bundle.ts +668 -81
  71. package/src/cfetch/index.ts +40 -3
  72. package/src/cfetch/internal.ts +144 -32
  73. package/src/cli.ts +4 -3
  74. package/src/config/config.ts +27 -3
  75. package/src/config/environment.ts +131 -7
  76. package/src/config/index.ts +128 -8
  77. package/src/config/validation-helpers.ts +19 -6
  78. package/src/config/validation.ts +411 -14
  79. package/src/config-cache.ts +3 -2
  80. package/src/create-worker-preview.ts +31 -6
  81. package/src/create-worker-upload-form.ts +84 -22
  82. package/src/d1/backups.tsx +223 -0
  83. package/src/d1/constants.ts +2 -0
  84. package/src/d1/create.tsx +63 -0
  85. package/src/d1/delete.tsx +56 -0
  86. package/src/d1/execute.tsx +352 -0
  87. package/src/d1/formatTimeAgo.ts +14 -0
  88. package/src/d1/index.ts +101 -0
  89. package/src/d1/list.tsx +48 -0
  90. package/src/d1/migrations/apply.tsx +196 -0
  91. package/src/d1/migrations/create.tsx +77 -0
  92. package/src/d1/migrations/helpers.ts +147 -0
  93. package/src/d1/migrations/index.tsx +3 -0
  94. package/src/d1/migrations/list.tsx +79 -0
  95. package/src/d1/migrations/options.ts +18 -0
  96. package/src/d1/options.ts +22 -0
  97. package/src/d1/types.tsx +24 -0
  98. package/src/d1/utils.ts +48 -0
  99. package/src/delete.ts +108 -0
  100. package/src/deployments.ts +83 -0
  101. package/src/deprecated/index.ts +145 -0
  102. package/src/dev/dev-vars.ts +11 -8
  103. package/src/dev/dev.tsx +220 -58
  104. package/src/dev/get-local-persistence-path.tsx +31 -0
  105. package/src/dev/local.tsx +740 -181
  106. package/src/dev/remote.tsx +340 -123
  107. package/src/dev/start-server.ts +543 -0
  108. package/src/dev/use-esbuild.ts +61 -7
  109. package/src/dev/validate-dev-props.ts +31 -0
  110. package/src/dev-registry.tsx +201 -0
  111. package/src/dev.tsx +614 -258
  112. package/src/dialogs.tsx +41 -8
  113. package/src/{worker-namespace.ts → dispatch-namespace.ts} +23 -22
  114. package/src/docs/index.ts +97 -0
  115. package/src/entry.ts +3 -2
  116. package/src/environment-variables/factory.ts +88 -0
  117. package/src/environment-variables/misc-variables.ts +30 -0
  118. package/src/generate/index.ts +300 -0
  119. package/src/git-client.ts +100 -7
  120. package/src/index.tsx +249 -1560
  121. package/src/init.ts +626 -150
  122. package/src/inspect.ts +137 -32
  123. package/src/{metrics/is-ci.ts → is-ci.ts} +0 -0
  124. package/src/is-interactive.ts +4 -0
  125. package/src/jest.d.ts +4 -0
  126. package/src/{kv.ts → kv/helpers.ts} +3 -3
  127. package/src/kv/index.ts +596 -0
  128. package/src/logger.ts +27 -8
  129. package/src/metrics/index.ts +1 -0
  130. package/src/metrics/metrics-config.ts +4 -4
  131. package/src/metrics/metrics-dispatcher.ts +1 -0
  132. package/src/metrics/metrics-usage-headers.ts +24 -0
  133. package/src/metrics/send-event.ts +13 -8
  134. package/src/miniflare-cli/assets.ts +172 -465
  135. package/src/miniflare-cli/index.ts +149 -24
  136. package/src/miniflare-cli/tsconfig.json +9 -0
  137. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -0
  138. package/src/miniflare-cli/types.ts +11 -0
  139. package/src/module-collection.ts +12 -3
  140. package/src/pages/build.tsx +108 -42
  141. package/src/pages/constants.ts +11 -0
  142. package/src/pages/deployment-tails.tsx +284 -0
  143. package/src/pages/deployments.tsx +9 -31
  144. package/src/pages/dev.tsx +417 -108
  145. package/src/pages/errors.ts +66 -0
  146. package/src/pages/functions/buildPlugin.ts +86 -84
  147. package/src/pages/functions/buildWorker.ts +121 -106
  148. package/src/pages/functions/routes-consolidation.test.ts +250 -0
  149. package/src/pages/functions/routes-consolidation.ts +73 -0
  150. package/src/pages/functions/routes-transformation.test.ts +282 -0
  151. package/src/pages/functions/routes-transformation.ts +115 -0
  152. package/src/pages/functions/routes-validation.test.ts +403 -0
  153. package/src/pages/functions/routes-validation.ts +202 -0
  154. package/src/pages/functions/tsconfig.json +8 -0
  155. package/src/pages/functions/tsconfig.tsbuildinfo +1 -0
  156. package/src/pages/functions.tsx +82 -0
  157. package/src/pages/hash.tsx +13 -0
  158. package/src/pages/index.tsx +73 -55
  159. package/src/pages/projects.tsx +9 -3
  160. package/src/pages/prompt-select-project.tsx +31 -0
  161. package/src/pages/publish.tsx +183 -60
  162. package/src/pages/types.ts +1 -0
  163. package/src/pages/upload.tsx +107 -56
  164. package/src/pages/utils.ts +13 -2
  165. package/src/paths.ts +49 -4
  166. package/src/proxy.ts +375 -157
  167. package/src/publish/index.ts +270 -0
  168. package/src/{publish.ts → publish/publish.ts} +431 -188
  169. package/src/pubsub/pubsub-commands.tsx +4 -3
  170. package/src/queues/cli/commands/consumer/add.ts +71 -0
  171. package/src/queues/cli/commands/consumer/index.ts +22 -0
  172. package/src/queues/cli/commands/consumer/remove.ts +38 -0
  173. package/src/queues/cli/commands/create.ts +25 -0
  174. package/src/queues/cli/commands/delete.ts +26 -0
  175. package/src/queues/cli/commands/index.ts +36 -0
  176. package/src/queues/cli/commands/list.ts +25 -0
  177. package/src/queues/client.ts +135 -0
  178. package/src/queues/utils.ts +18 -0
  179. package/src/r2/constants.ts +4 -0
  180. package/src/r2/helpers.ts +131 -0
  181. package/src/r2/index.ts +289 -0
  182. package/src/routes.ts +140 -0
  183. package/src/secret/index.ts +379 -0
  184. package/src/sites.tsx +3 -3
  185. package/src/tail/createTail.ts +379 -0
  186. package/src/tail/filters.ts +4 -6
  187. package/src/tail/index.ts +199 -284
  188. package/src/tail/printing.ts +43 -3
  189. package/src/tsconfig-sanity.ts +16 -0
  190. package/src/type-generation.ts +181 -0
  191. package/src/user/access.ts +68 -0
  192. package/src/user/auth-variables.ts +113 -0
  193. package/src/user/choose-account.tsx +1 -1
  194. package/src/user/index.ts +0 -1
  195. package/src/user/user.tsx +116 -49
  196. package/src/utils/collectKeyValues.ts +14 -0
  197. package/src/whoami.tsx +80 -2
  198. package/src/worker.ts +69 -9
  199. package/src/yargs-types.ts +24 -0
  200. package/src/zones.ts +124 -9
  201. package/templates/__tests__/pages-dev-util.test.ts +128 -0
  202. package/templates/__tests__/tsconfig-sanity.ts +12 -0
  203. package/templates/__tests__/tsconfig.json +8 -0
  204. package/templates/__tests__/tsconfig.tsbuildinfo +1 -0
  205. package/templates/d1-beta-facade.js +205 -0
  206. package/templates/facade.d.ts +14 -0
  207. package/templates/first-party-worker-module-facade.ts +19 -0
  208. package/templates/format-dev-errors.ts +33 -0
  209. package/templates/init-tests/test-jest-new-worker.js +23 -0
  210. package/templates/init-tests/test-vitest-new-worker.js +24 -0
  211. package/templates/init-tests/test-vitest-new-worker.ts +25 -0
  212. package/templates/middleware/common.ts +62 -0
  213. package/templates/middleware/loader-modules.ts +82 -0
  214. package/templates/middleware/loader-sw.ts +233 -0
  215. package/templates/middleware/middleware-miniflare3-json-error.ts +20 -0
  216. package/templates/middleware/middleware-pretty-error.ts +40 -0
  217. package/templates/middleware/middleware-scheduled.ts +15 -0
  218. package/templates/new-worker.js +1 -1
  219. package/templates/pages-dev-pipeline.ts +31 -0
  220. package/templates/pages-dev-util.ts +52 -0
  221. package/templates/pages-shim.ts +4 -1
  222. package/templates/pages-template-plugin.ts +21 -5
  223. package/templates/pages-template-worker.ts +37 -9
  224. package/templates/{static-asset-facade.js → serve-static-assets.ts} +23 -7
  225. package/templates/service-bindings-module-facade.js +54 -0
  226. package/templates/service-bindings-sw-facade.js +42 -0
  227. package/templates/tsconfig-sanity.ts +11 -0
  228. package/templates/tsconfig.init.json +106 -0
  229. package/templates/tsconfig.json +5 -102
  230. package/templates/tsconfig.tsbuildinfo +1 -0
  231. package/wrangler-dist/cli.d.ts +621 -42
  232. package/wrangler-dist/cli.js +144441 -102606
  233. package/src/environment-variables.ts +0 -35
  234. package/src/faye-websocket.d.ts +0 -6
  235. package/src/generate.ts +0 -33
  236. package/src/miniflare-cli/enum-keys.ts +0 -17
  237. package/src/preview.ts +0 -31
  238. package/src/r2.ts +0 -50
  239. package/src/user/env-vars.ts +0 -46
@@ -1,15 +1,23 @@
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
6
  import { useMockIsTTY } from "./helpers/mock-istty";
7
+ import { msw, mswSucessScriptHandlers } from "./helpers/msw";
7
8
  import { runInTempDir } from "./helpers/run-in-tmp";
8
9
  import { runWrangler } from "./helpers/run-wrangler";
9
- import type { TailEventMessage, RequestEvent, ScheduledEvent } from "../tail";
10
+ import type {
11
+ TailEventMessage,
12
+ RequestEvent,
13
+ ScheduledEvent,
14
+ AlarmEvent,
15
+ } from "../tail/createTail";
16
+ import type { RequestInit } from "undici";
10
17
  import type WebSocket from "ws";
11
18
 
12
19
  describe("tail", () => {
20
+ beforeEach(() => msw.use(...mswSucessScriptHandlers));
13
21
  runInTempDir();
14
22
  mockAccountId();
15
23
  mockApiToken();
@@ -19,7 +27,6 @@ describe("tail", () => {
19
27
  afterEach(() => {
20
28
  mockWebSockets.forEach((ws) => ws.close());
21
29
  mockWebSockets.splice(0);
22
- unsetAllMocks();
23
30
  });
24
31
 
25
32
  /**
@@ -27,6 +34,7 @@ describe("tail", () => {
27
34
  * deletion, and connection.
28
35
  */
29
36
  describe("API interaction", () => {
37
+ const { setIsTTY } = useMockIsTTY();
30
38
  it("should throw an error if name isn't provided", async () => {
31
39
  await expect(
32
40
  runWrangler("tail")
@@ -34,52 +42,159 @@ describe("tail", () => {
34
42
  `"Required Worker name missing. Please specify the Worker name in wrangler.toml, or pass it as an argument with \`wrangler tail <worker-name>\`"`
35
43
  );
36
44
  });
37
-
45
+ it("warns about durable object restarts for tty", async () => {
46
+ setIsTTY(true);
47
+ const api = mockWebsocketAPIs();
48
+ expect(api.requests.creation.length).toStrictEqual(0);
49
+ await runWrangler("tail durable-object--websocket--response");
50
+ expect(std.out).toMatchInlineSnapshot(`""`);
51
+ expect(std.warn).toMatchInlineSnapshot(`
52
+ "▲ [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.
53
+
54
+ "
55
+ `);
56
+ expect(std.err).toMatchInlineSnapshot(`""`);
57
+ });
38
58
  it("creates and then delete tails", async () => {
39
59
  const api = mockWebsocketAPIs();
40
- expect(api.requests.creation.count).toStrictEqual(0);
60
+ expect(api.requests.creation.length).toStrictEqual(0);
41
61
 
42
62
  await runWrangler("tail test-worker");
43
63
 
44
64
  await expect(api.ws.connected).resolves.toBeTruthy();
45
- expect(api.requests.creation.count).toStrictEqual(1);
65
+ expect(api.requests.creation.length).toStrictEqual(1);
46
66
  expect(api.requests.deletion.count).toStrictEqual(0);
47
67
 
48
- api.ws.close();
68
+ await api.closeHelper();
49
69
  expect(api.requests.deletion.count).toStrictEqual(1);
50
70
  });
71
+ it("should connect to the worker assigned to a given route", async () => {
72
+ const api = mockWebsocketAPIs();
73
+ expect(api.requests.creation.length).toStrictEqual(0);
74
+
75
+ msw.use(
76
+ rest.get(`*/zones`, (req, res, ctx) => {
77
+ expect(req.url.searchParams.get("name")).toBe("example.com");
78
+ return res.once(
79
+ ctx.status(200),
80
+ ctx.json({
81
+ success: true,
82
+ errors: [],
83
+ messages: [],
84
+ result: [{ id: "test-zone" }],
85
+ })
86
+ );
87
+ })
88
+ );
89
+ msw.use(
90
+ rest.get(`*/zones/:zoneId/workers/routes`, (req, res, ctx) => {
91
+ return res.once(
92
+ ctx.status(200),
93
+ ctx.json({
94
+ success: true,
95
+ errors: [],
96
+ messages: [],
97
+ result: [
98
+ {
99
+ pattern: "example.com/*",
100
+ script: "test-worker",
101
+ },
102
+ ],
103
+ })
104
+ );
105
+ })
106
+ );
107
+ await runWrangler("tail example.com/*");
108
+
109
+ await expect(api.ws.connected).resolves.toBeTruthy();
110
+ expect(api.requests.creation.length).toStrictEqual(1);
111
+ expect(api.requests.deletion.count).toStrictEqual(0);
112
+
113
+ await api.closeHelper();
114
+ expect(api.requests.deletion.count).toStrictEqual(1);
115
+ });
116
+
117
+ it("should error if a given route is not assigned to the user's zone", async () => {
118
+ msw.use(
119
+ rest.get(`*/zones`, (req, res, ctx) => {
120
+ expect(req.url.searchParams.get("name")).toBe("example.com");
121
+ return res.once(
122
+ ctx.status(200),
123
+ ctx.json({
124
+ success: true,
125
+ errors: [],
126
+ messages: [],
127
+ result: [{ id: "test-zone" }],
128
+ })
129
+ );
130
+ })
131
+ );
132
+ msw.use(
133
+ rest.get(`*/zones/:zoneId/workers/routes`, (req, res, ctx) => {
134
+ return res.once(
135
+ ctx.status(200),
136
+ ctx.json({
137
+ success: true,
138
+ errors: [],
139
+ messages: [],
140
+ result: [],
141
+ })
142
+ );
143
+ })
144
+ );
145
+
146
+ await expect(runWrangler("tail example.com/*")).rejects.toThrow();
147
+ });
148
+ it("should error if a given route is not within the user's zone", async () => {
149
+ msw.use(
150
+ rest.get(`*/zones`, (req, res, ctx) => {
151
+ expect(req.url.searchParams.get("name")).toBe("example.com");
152
+ return res.once(
153
+ ctx.status(200),
154
+ ctx.json({
155
+ success: true,
156
+ errors: [],
157
+ messages: [],
158
+ result: [],
159
+ })
160
+ );
161
+ })
162
+ );
163
+
164
+ await expect(runWrangler("tail example.com/*")).rejects.toThrow();
165
+ });
51
166
 
52
167
  it("creates and then delete tails: legacy envs", async () => {
53
168
  const api = mockWebsocketAPIs("some-env", true);
54
- expect(api.requests.creation.count).toStrictEqual(0);
169
+ expect(api.requests.creation.length).toStrictEqual(0);
55
170
 
56
171
  await runWrangler("tail test-worker --env some-env --legacy-env true");
57
172
 
58
173
  await expect(api.ws.connected).resolves.toBeTruthy();
59
- expect(api.requests.creation.count).toStrictEqual(1);
174
+ expect(api.requests.creation.length).toStrictEqual(1);
60
175
  expect(api.requests.deletion.count).toStrictEqual(0);
61
176
 
62
- api.ws.close();
177
+ await api.closeHelper();
63
178
  expect(api.requests.deletion.count).toStrictEqual(1);
64
179
  });
65
180
 
66
181
  it("creates and then delete tails: service envs", async () => {
67
182
  const api = mockWebsocketAPIs("some-env");
68
- expect(api.requests.creation.count).toStrictEqual(0);
183
+ expect(api.requests.creation.length).toStrictEqual(0);
69
184
 
70
185
  await runWrangler("tail test-worker --env some-env --legacy-env false");
71
186
 
72
187
  await expect(api.ws.connected).resolves.toBeTruthy();
73
- expect(api.requests.creation.count).toStrictEqual(1);
188
+ expect(api.requests.creation.length).toStrictEqual(1);
74
189
  expect(api.requests.deletion.count).toStrictEqual(0);
75
190
 
76
- api.ws.close();
191
+ await api.closeHelper();
77
192
  expect(api.requests.deletion.count).toStrictEqual(1);
78
193
  });
79
194
 
80
195
  it("errors when the websocket closes unexpectedly", async () => {
81
196
  const api = mockWebsocketAPIs();
82
- api.ws.close();
197
+ await api.closeHelper();
83
198
 
84
199
  await expect(runWrangler("tail test-worker")).rejects.toThrow();
85
200
  });
@@ -104,57 +219,72 @@ describe("tail", () => {
104
219
  await expect(tooLow).rejects.toThrow();
105
220
 
106
221
  await runWrangler("tail test-worker --sampling-rate 0.25");
107
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
108
- { sampling_rate: 0.25 },
109
- ]);
222
+
223
+ expect(api.requests.creation[0]).toEqual({
224
+ filters: [{ sampling_rate: 0.25 }],
225
+ });
110
226
  });
111
227
 
112
228
  it("sends single status filters", async () => {
113
229
  const api = mockWebsocketAPIs();
114
230
  await runWrangler("tail test-worker --status error");
115
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
116
- { outcome: ["exception", "exceededCpu", "unknown"] },
117
- ]);
231
+ expect(api.requests.creation[0]).toEqual({
232
+ filters: [
233
+ {
234
+ outcome: ["exception", "exceededCpu", "exceededMemory", "unknown"],
235
+ },
236
+ ],
237
+ });
118
238
  });
119
239
 
120
240
  it("sends multiple status filters", async () => {
121
241
  const api = mockWebsocketAPIs();
122
242
  await runWrangler("tail test-worker --status error --status canceled");
123
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
124
- { outcome: ["exception", "exceededCpu", "unknown", "canceled"] },
125
- ]);
243
+ expect(api.requests.creation[0]).toEqual({
244
+ filters: [
245
+ {
246
+ outcome: [
247
+ "exception",
248
+ "exceededCpu",
249
+ "exceededMemory",
250
+ "unknown",
251
+ "canceled",
252
+ ],
253
+ },
254
+ ],
255
+ });
126
256
  });
127
257
 
128
258
  it("sends single HTTP method filters", async () => {
129
259
  const api = mockWebsocketAPIs();
130
260
  await runWrangler("tail test-worker --method POST");
131
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
132
- { method: ["POST"] },
133
- ]);
261
+ expect(api.requests.creation[0]).toEqual({
262
+ filters: [{ method: ["POST"] }],
263
+ });
134
264
  });
135
265
 
136
266
  it("sends multiple HTTP method filters", async () => {
137
267
  const api = mockWebsocketAPIs();
138
268
  await runWrangler("tail test-worker --method POST --method GET");
139
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
140
- { method: ["POST", "GET"] },
141
- ]);
269
+ expect(api.requests.creation[0]).toEqual({
270
+ filters: [{ method: ["POST", "GET"] }],
271
+ });
142
272
  });
143
273
 
144
274
  it("sends header filters without a query", async () => {
145
275
  const api = mockWebsocketAPIs();
146
276
  await runWrangler("tail test-worker --header X-CUSTOM-HEADER");
147
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
148
- { header: { key: "X-CUSTOM-HEADER" } },
149
- ]);
277
+ expect(api.requests.creation[0]).toEqual({
278
+ filters: [{ header: { key: "X-CUSTOM-HEADER" } }],
279
+ });
150
280
  });
151
281
 
152
282
  it("sends header filters with a query", async () => {
153
283
  const api = mockWebsocketAPIs();
154
284
  await runWrangler("tail test-worker --header X-CUSTOM-HEADER:some-value");
155
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
156
- { header: { key: "X-CUSTOM-HEADER", query: "some-value" } },
157
- ]);
285
+ expect(api.requests.creation[0]).toEqual({
286
+ filters: [{ header: { key: "X-CUSTOM-HEADER", query: "some-value" } }],
287
+ });
158
288
  });
159
289
 
160
290
  it("sends single IP filters", async () => {
@@ -162,9 +292,9 @@ describe("tail", () => {
162
292
  const fakeIp = "192.0.2.1";
163
293
 
164
294
  await runWrangler(`tail test-worker --ip ${fakeIp}`);
165
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
166
- { client_ip: [fakeIp] },
167
- ]);
295
+ expect(api.requests.creation[0]).toEqual({
296
+ filters: [{ client_ip: [fakeIp] }],
297
+ });
168
298
  });
169
299
 
170
300
  it("sends multiple IP filters", async () => {
@@ -172,9 +302,9 @@ describe("tail", () => {
172
302
  const fakeIp = "192.0.2.1";
173
303
 
174
304
  await runWrangler(`tail test-worker --ip ${fakeIp} --ip self`);
175
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
176
- { client_ip: [fakeIp, "self"] },
177
- ]);
305
+ expect(api.requests.creation[0]).toEqual({
306
+ filters: [{ client_ip: [fakeIp, "self"] }],
307
+ });
178
308
  });
179
309
 
180
310
  it("sends search filters", async () => {
@@ -182,9 +312,9 @@ describe("tail", () => {
182
312
  const search = "filterMe";
183
313
 
184
314
  await runWrangler(`tail test-worker --search ${search}`);
185
- await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
186
- { query: search },
187
- ]);
315
+ expect(api.requests.creation[0]).toEqual({
316
+ filters: [{ query: search }],
317
+ });
188
318
  });
189
319
 
190
320
  it("sends everything but the kitchen sink", async () => {
@@ -207,20 +337,25 @@ describe("tail", () => {
207
337
 
208
338
  const expectedWebsocketMessage = {
209
339
  filters: [
210
- { sampling_rate },
211
- { outcome: ["ok", "exception", "exceededCpu", "unknown"] },
212
- { method },
340
+ { sampling_rate: 0.69 },
341
+ {
342
+ outcome: [
343
+ "ok",
344
+ "exception",
345
+ "exceededCpu",
346
+ "exceededMemory",
347
+ "unknown",
348
+ ],
349
+ },
350
+ { method: ["GET", "POST", "PUT"] },
213
351
  { header: { key: "X-HELLO", query: "world" } },
214
- { client_ip },
215
- { query },
352
+ { client_ip: ["192.0.2.1", "self"] },
353
+ { query: "onlyTheseMessagesPlease" },
216
354
  ],
217
- debug: true,
218
355
  };
219
356
 
220
357
  await runWrangler(`tail test-worker ${cliFilters}`);
221
- await expect(api.nextMessageJson()).resolves.toEqual(
222
- expectedWebsocketMessage
223
- );
358
+ expect(api.requests.creation[0]).toEqual(expectedWebsocketMessage);
224
359
  });
225
360
  });
226
361
 
@@ -251,6 +386,18 @@ describe("tail", () => {
251
386
  expect(std.out).toMatch(deserializeToJson(serializedMessage));
252
387
  });
253
388
 
389
+ it("logs alarm messages in json format", async () => {
390
+ const api = mockWebsocketAPIs();
391
+ await runWrangler("tail test-worker --format json");
392
+
393
+ const event = generateMockAlarmEvent();
394
+ const message = generateMockEventMessage({ event });
395
+ const serializedMessage = serialize(message);
396
+
397
+ api.ws.send(serializedMessage);
398
+ expect(std.out).toMatch(deserializeToJson(serializedMessage));
399
+ });
400
+
254
401
  it("logs request messages in pretty format", async () => {
255
402
  const api = mockWebsocketAPIs();
256
403
  await runWrangler("tail test-worker --format pretty");
@@ -266,15 +413,12 @@ describe("tail", () => {
266
413
  new Date(mockEventTimestamp).toLocaleString(),
267
414
  "[mock event timestamp]"
268
415
  )
269
- .replace(
270
- mockTailExpiration.toLocaleString(),
271
- "[mock expiration date]"
272
- )
416
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
273
417
  ).toMatchInlineSnapshot(`
274
- "Successfully created tail, expires at [mock expiration date]
275
- Connected to test-worker, waiting for logs...
276
- GET https://example.org/ - Ok @ [mock event timestamp]"
277
- `);
418
+ "Successfully created tail, expires at [mock expiration date]
419
+ Connected to test-worker, waiting for logs...
420
+ GET https://example.org/ - Ok @ [mock event timestamp]"
421
+ `);
278
422
  });
279
423
 
280
424
  it("logs scheduled messages in pretty format", async () => {
@@ -292,15 +436,35 @@ describe("tail", () => {
292
436
  new Date(mockEventTimestamp).toLocaleString(),
293
437
  "[mock timestamp string]"
294
438
  )
439
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
440
+ ).toMatchInlineSnapshot(`
441
+ "Successfully created tail, expires at [mock expiration date]
442
+ Connected to test-worker, waiting for logs...
443
+ \\"* * * * *\\" @ [mock timestamp string] - Ok"
444
+ `);
445
+ });
446
+
447
+ it("logs alarm messages in pretty format", async () => {
448
+ const api = mockWebsocketAPIs();
449
+ await runWrangler("tail test-worker --format pretty");
450
+
451
+ const event = generateMockAlarmEvent();
452
+ const message = generateMockEventMessage({ event });
453
+ const serializedMessage = serialize(message);
454
+
455
+ api.ws.send(serializedMessage);
456
+ expect(
457
+ std.out
295
458
  .replace(
296
- mockTailExpiration.toLocaleString(),
297
- "[mock expiration date]"
459
+ new Date(mockEventScheduledTime).toLocaleString(),
460
+ "[mock scheduled time]"
298
461
  )
462
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
299
463
  ).toMatchInlineSnapshot(`
300
- "Successfully created tail, expires at [mock expiration date]
301
- Connected to test-worker, waiting for logs...
302
- \\"* * * * *\\" @ [mock timestamp string] - Ok"
303
- `);
464
+ "Successfully created tail, expires at [mock expiration date]
465
+ Connected to test-worker, waiting for logs...
466
+ Alarm @ [mock scheduled time] - Ok"
467
+ `);
304
468
  });
305
469
 
306
470
  it("should not crash when the tail message has a void event", async () => {
@@ -317,15 +481,12 @@ describe("tail", () => {
317
481
  new Date(mockEventTimestamp).toLocaleString(),
318
482
  "[mock timestamp string]"
319
483
  )
320
- .replace(
321
- mockTailExpiration.toLocaleString(),
322
- "[mock expiration date]"
323
- )
484
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
324
485
  ).toMatchInlineSnapshot(`
325
- "Successfully created tail, expires at [mock expiration date]
326
- Connected to test-worker, waiting for logs...
327
- [missing request] - Ok @ [mock timestamp string]"
328
- `);
486
+ "Successfully created tail, expires at [mock expiration date]
487
+ Connected to test-worker, waiting for logs...
488
+ Unknown Event - Ok @ [mock timestamp string]"
489
+ `);
329
490
  });
330
491
 
331
492
  it("defaults to logging in pretty format when the output is a TTY", async () => {
@@ -344,15 +505,12 @@ describe("tail", () => {
344
505
  new Date(mockEventTimestamp).toLocaleString(),
345
506
  "[mock event timestamp]"
346
507
  )
347
- .replace(
348
- mockTailExpiration.toLocaleString(),
349
- "[mock expiration date]"
350
- )
508
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
351
509
  ).toMatchInlineSnapshot(`
352
- "Successfully created tail, expires at [mock expiration date]
353
- Connected to test-worker, waiting for logs...
354
- GET https://example.org/ - Ok @ [mock event timestamp]"
355
- `);
510
+ "Successfully created tail, expires at [mock expiration date]
511
+ Connected to test-worker, waiting for logs...
512
+ GET https://example.org/ - Ok @ [mock event timestamp]"
513
+ `);
356
514
  });
357
515
 
358
516
  it("defaults to logging in json format when the output is not a TTY", async () => {
@@ -400,26 +558,23 @@ describe("tail", () => {
400
558
  new Date(mockEventTimestamp).toLocaleString(),
401
559
  "[mock event timestamp]"
402
560
  )
403
- .replace(
404
- mockTailExpiration.toLocaleString(),
405
- "[mock expiration date]"
406
- )
561
+ .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
407
562
  ).toMatchInlineSnapshot(`
408
- "Successfully created tail, expires at [mock expiration date]
409
- Connected to test-worker, waiting for logs...
410
- GET https://example.org/ - Ok @ [mock event timestamp]
411
- (log) some string
412
- (log) { complex: 'object' }
413
- (error) 1234"
414
- `);
563
+ "Successfully created tail, expires at [mock expiration date]
564
+ Connected to test-worker, waiting for logs...
565
+ GET https://example.org/ - Ok @ [mock event timestamp]
566
+ (log) some string
567
+ (log) { complex: 'object' }
568
+ (error) 1234"
569
+ `);
415
570
  expect(std.err).toMatchInlineSnapshot(`
416
- "X [ERROR]  Error: some error
571
+ "X [ERROR]  Error: some error
417
572
 
418
573
 
419
- X [ERROR]  Error: { complex: 'error' }
574
+ X [ERROR]  Error: { complex: 'error' }
420
575
 
421
- "
422
- `);
576
+ "
577
+ `);
423
578
  expect(std.warn).toMatchInlineSnapshot(`""`);
424
579
  });
425
580
  });
@@ -437,8 +592,8 @@ describe("tail", () => {
437
592
  * @returns the same type we expect when deserializing in wrangler
438
593
  */
439
594
  function serialize(message: TailEventMessage): WebSocket.RawData {
440
- if (isScheduled(message.event)) {
441
- // `ScheduledEvent`s work just fine
595
+ if (!isRequest(message.event)) {
596
+ // `ScheduledEvent`s and `TailEvent`s work just fine
442
597
  const stringified = JSON.stringify(message);
443
598
  return Buffer.from(stringified, "utf-8");
444
599
  } else {
@@ -470,12 +625,12 @@ function serialize(message: TailEventMessage): WebSocket.RawData {
470
625
  * Small helper to disambiguate the event types possible in a `TailEventMessage`
471
626
  *
472
627
  * @param event A TailEvent
473
- * @returns whether event is a ScheduledEvent (true) or a RequestEvent
628
+ * @returns true if `event` is a RequestEvent
474
629
  */
475
- function isScheduled(
476
- event: ScheduledEvent | RequestEvent | undefined | null
477
- ): event is ScheduledEvent {
478
- return Boolean(event && "cron" in event);
630
+ function isRequest(
631
+ event: ScheduledEvent | RequestEvent | AlarmEvent | undefined | null
632
+ ): event is RequestEvent {
633
+ return Boolean(event && "request" in event);
479
634
  }
480
635
 
481
636
  /**
@@ -496,11 +651,12 @@ function deserializeToJson(message: WebSocket.RawData): string {
496
651
  */
497
652
  type MockAPI = {
498
653
  requests: {
499
- creation: RequestCounter;
654
+ creation: RequestInit[];
500
655
  deletion: RequestCounter;
501
656
  };
502
657
  ws: MockWebSocket;
503
658
  nextMessageJson(): Promise<unknown>;
659
+ closeHelper: () => Promise<void>;
504
660
  };
505
661
 
506
662
  /**
@@ -521,29 +677,38 @@ type RequestCounter = {
521
677
  function mockCreateTailRequest(
522
678
  websocketURL: string,
523
679
  env?: string,
524
- legacyEnv = false
525
- ): RequestCounter {
526
- const requests = { count: 0 };
680
+ legacyEnv = false,
681
+ expectedScriptName = legacyEnv && env ? `test-worker-${env}` : "test-worker"
682
+ ): RequestInit[] {
683
+ const requests: RequestInit[] = [];
527
684
  const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
528
685
  const environment = env && !legacyEnv ? "/environments/:envName" : "";
529
- setMockResponse(
530
- `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails`,
531
- "POST",
532
- ([_url, accountId, scriptName, envName]) => {
533
- requests.count++;
534
- expect(accountId).toEqual("some-account-id");
535
- expect(scriptName).toEqual(
536
- legacyEnv && env ? `test-worker-${env}` : "test-worker"
537
- );
538
- if (!legacyEnv) {
539
- expect(envName).toEqual(env);
686
+ msw.use(
687
+ rest.post(
688
+ `*/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails`,
689
+ async (req, res, ctx) => {
690
+ const request = await req.json();
691
+ requests.push(request);
692
+ expect(req.params.accountId).toEqual("some-account-id");
693
+ expect(req.params.scriptName).toEqual(expectedScriptName);
694
+ if (!legacyEnv) {
695
+ expect(req.params.envName).toEqual(env);
696
+ }
697
+ return res.once(
698
+ ctx.status(200),
699
+ ctx.json({
700
+ success: true,
701
+ errors: [],
702
+ messages: [],
703
+ result: {
704
+ url: websocketURL,
705
+ id: "tail-id",
706
+ expires_at: mockTailExpiration,
707
+ },
708
+ })
709
+ );
540
710
  }
541
- return {
542
- id: "tail-id",
543
- url: websocketURL,
544
- expires_at: mockTailExpiration,
545
- };
546
- }
711
+ )
547
712
  );
548
713
 
549
714
  return requests;
@@ -559,6 +724,11 @@ const mockTailExpiration = new Date(3005, 1);
559
724
  */
560
725
  const mockEventTimestamp = 1645454470467;
561
726
 
727
+ /**
728
+ * Default value for event time ISO strings
729
+ */
730
+ const mockEventScheduledTime = new Date(mockEventTimestamp).toISOString();
731
+
562
732
  /**
563
733
  * Mock out the API hit during Tail deletion
564
734
  *
@@ -566,33 +736,36 @@ const mockEventTimestamp = 1645454470467;
566
736
  */
567
737
  function mockDeleteTailRequest(
568
738
  env?: string,
569
- legacyEnv = false
739
+ legacyEnv = false,
740
+ expectedScriptName = legacyEnv && env ? `test-worker-${env}` : "test-worker"
570
741
  ): RequestCounter {
571
742
  const requests = { count: 0 };
572
743
  const servicesOrScripts = env && !legacyEnv ? "services" : "scripts";
573
744
  const environment = env && !legacyEnv ? "/environments/:envName" : "";
574
- setMockResponse(
575
- // "/accounts/:accountId/workers/scripts/:worker/tails",
576
- `/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails/:tailId`,
577
- "DELETE",
578
- ([_url, accountId, scriptName, envNameOrTailId, tailId]) => {
579
- requests.count++;
580
- expect(accountId).toEqual("some-account-id");
581
- expect(scriptName).toEqual(
582
- legacyEnv && env ? `test-worker-${env}` : "test-worker"
583
- );
584
- if (!legacyEnv) {
585
- if (env) {
586
- expect(envNameOrTailId).toEqual(env);
587
- expect(tailId).toEqual("tail-id");
588
- } else {
589
- expect(envNameOrTailId).toEqual("tail-id");
745
+ msw.use(
746
+ rest.delete(
747
+ `*/accounts/:accountId/workers/${servicesOrScripts}/:scriptName${environment}/tails/:tailId`,
748
+ async (req, res, ctx) => {
749
+ requests.count++;
750
+ expect(req.params.accountId).toEqual("some-account-id");
751
+ expect(req.params.scriptName).toEqual(expectedScriptName);
752
+ if (!legacyEnv) {
753
+ if (env) {
754
+ expect(req.params.tailId).toEqual("tail-id");
755
+ }
590
756
  }
591
- } else {
592
- expect(envNameOrTailId).toEqual("tail-id");
757
+ expect(req.params.tailId).toEqual("tail-id");
758
+ return res(
759
+ ctx.status(200),
760
+ ctx.json({
761
+ success: true,
762
+ errors: [],
763
+ messages: [],
764
+ result: null,
765
+ })
766
+ );
593
767
  }
594
- return null;
595
- }
768
+ )
596
769
  );
597
770
 
598
771
  return requests;
@@ -607,12 +780,16 @@ const mockWebSockets: MockWebSocket[] = [];
607
780
  * @param websocketURL a fake websocket URL for wrangler to connect to
608
781
  * @returns a mocked-out version of the API
609
782
  */
610
- function mockWebsocketAPIs(env?: string, legacyEnv = false): MockAPI {
783
+ function mockWebsocketAPIs(
784
+ env?: string,
785
+ legacyEnv = false,
786
+ expectedScriptName?: string
787
+ ): MockAPI {
611
788
  const websocketURL = "ws://localhost:1234";
612
789
  const api: MockAPI = {
613
790
  requests: {
614
791
  deletion: { count: 0 },
615
- creation: { count: 0 },
792
+ creation: [],
616
793
  },
617
794
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
618
795
  ws: null!, // will be set in the `beforeEach()` below.
@@ -625,9 +802,27 @@ function mockWebsocketAPIs(env?: string, legacyEnv = false): MockAPI {
625
802
  const message = await api.ws.nextMessage;
626
803
  return JSON.parse(message as string);
627
804
  },
805
+ /**
806
+ * Close the mock websocket and clean up the API.
807
+ * The setTimeout forces a cycle to allow for closing and cleanup
808
+ * @returns a Promise that resolves when the websocket is closed
809
+ */
810
+ async closeHelper() {
811
+ api.ws.close();
812
+ await new Promise((resolve) => setTimeout(resolve, 0));
813
+ },
628
814
  };
629
- api.requests.creation = mockCreateTailRequest(websocketURL, env, legacyEnv);
630
- api.requests.deletion = mockDeleteTailRequest(env, legacyEnv);
815
+ api.requests.creation = mockCreateTailRequest(
816
+ websocketURL,
817
+ env,
818
+ legacyEnv,
819
+ expectedScriptName
820
+ );
821
+ api.requests.deletion = mockDeleteTailRequest(
822
+ env,
823
+ legacyEnv,
824
+ expectedScriptName
825
+ );
631
826
  api.ws = new MockWebSocket(websocketURL);
632
827
  mockWebSockets.push(api.ws);
633
828
 
@@ -696,3 +891,9 @@ function generateMockScheduledEvent(
696
891
  scheduledTime: opts?.scheduledTime || mockEventTimestamp,
697
892
  };
698
893
  }
894
+
895
+ function generateMockAlarmEvent(opts?: Partial<AlarmEvent>): AlarmEvent {
896
+ return {
897
+ scheduledTime: opts?.scheduledTime || mockEventScheduledTime,
898
+ };
899
+ }