wrangler 2.18.0 → 2.20.0

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 (59) hide show
  1. package/miniflare-dist/index.mjs +1 -1
  2. package/package.json +1 -1
  3. package/src/__tests__/configuration.test.ts +8 -0
  4. package/src/__tests__/constellation.test.ts +371 -0
  5. package/src/__tests__/index.test.ts +2 -0
  6. package/src/__tests__/mtls-certificates.test.ts +1 -0
  7. package/src/__tests__/pages/functions-build.test.ts +76 -0
  8. package/src/__tests__/pages-deployment-tail.test.ts +2 -0
  9. package/src/__tests__/publish.test.ts +3 -3
  10. package/src/__tests__/tail.test.ts +38 -7
  11. package/src/__tests__/tsconfig.tsbuildinfo +1 -1
  12. package/src/__tests__/user.test.ts +1 -1
  13. package/src/api/dev.ts +5 -0
  14. package/src/api/pages/create-worker-bundle-contents.ts +1 -0
  15. package/src/api/pages/publish.tsx +28 -12
  16. package/src/bundle.ts +28 -7
  17. package/src/config/environment.ts +7 -0
  18. package/src/config/validation.ts +27 -0
  19. package/src/constellation/createProject.tsx +51 -0
  20. package/src/constellation/deleteProject.ts +51 -0
  21. package/src/constellation/deleteProjectModel.ts +68 -0
  22. package/src/constellation/index.ts +75 -0
  23. package/src/constellation/listCatalog.tsx +35 -0
  24. package/src/constellation/listModel.tsx +41 -0
  25. package/src/constellation/listProject.tsx +28 -0
  26. package/src/constellation/listRuntime.tsx +28 -0
  27. package/src/constellation/options.ts +17 -0
  28. package/src/constellation/types.ts +17 -0
  29. package/src/constellation/uploadModel.tsx +64 -0
  30. package/src/constellation/utils.ts +90 -0
  31. package/src/create-worker-upload-form.ts +4 -0
  32. package/src/dev/dev.tsx +6 -1
  33. package/src/dev/local.tsx +4 -0
  34. package/src/dev/remote.tsx +3 -0
  35. package/src/dev/start-server.ts +50 -39
  36. package/src/dev/use-esbuild.ts +54 -42
  37. package/src/dev.tsx +9 -4
  38. package/src/entry.ts +8 -1
  39. package/src/environment-variables/factory.ts +2 -1
  40. package/src/index.ts +10 -0
  41. package/src/init.ts +5 -0
  42. package/src/inspect.ts +107 -6
  43. package/src/logger.ts +5 -1
  44. package/src/miniflare-cli/tsconfig.tsbuildinfo +1 -1
  45. package/src/pages/build.ts +30 -17
  46. package/src/pages/dev.ts +24 -6
  47. package/src/pages/functions/buildPlugin.ts +1 -0
  48. package/src/pages/functions/buildWorker.ts +59 -0
  49. package/src/pages/functions/tsconfig.tsbuildinfo +1 -1
  50. package/src/publish/publish.ts +6 -1
  51. package/src/secret/index.ts +1 -0
  52. package/src/tail/createTail.ts +9 -0
  53. package/src/tail/printing.ts +10 -0
  54. package/src/traverse-module-graph.ts +1 -0
  55. package/src/user/user.ts +1 -0
  56. package/src/utils/render.ts +1 -1
  57. package/src/worker.ts +5 -0
  58. package/wrangler-dist/cli.d.ts +13 -2
  59. package/wrangler-dist/cli.js +3879 -3264
@@ -180,7 +180,7 @@ function mergeHeaders(base, extra) {
180
180
  });
181
181
  }
182
182
  function stripLeadingDoubleSlashes(location) {
183
- return location.replace(/^(\/|%2F|%2f|%5C|%5c|\\)+(.*)/, "/$2");
183
+ return location.replace(/^(\/|%2F|%2f|%5C|%5c|%09|\s|\\)+(.*)/, "/$2");
184
184
  }
185
185
  var OkResponse, MovedPermanentlyResponse, FoundResponse, NotModifiedResponse, PermanentRedirectResponse, NotFoundResponse, MethodNotAllowedResponse, NotAcceptableResponse, InternalServerErrorResponse, SeeOtherResponse, TemporaryRedirectResponse;
186
186
  var init_responses = __esm({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrangler",
3
- "version": "2.18.0",
3
+ "version": "2.20.0",
4
4
  "description": "Command-line interface for all things Cloudflare Workers",
5
5
  "keywords": [
6
6
  "wrangler",
@@ -84,6 +84,7 @@ describe("normalizeAndValidateConfig()", () => {
84
84
  first_party_worker: undefined,
85
85
  keep_vars: undefined,
86
86
  logpush: undefined,
87
+ placement: undefined,
87
88
  });
88
89
  expect(diagnostics.hasErrors()).toBe(false);
89
90
  expect(diagnostics.hasWarnings()).toBe(false);
@@ -955,6 +956,9 @@ describe("normalizeAndValidateConfig()", () => {
955
956
  node_compat: true,
956
957
  first_party_worker: true,
957
958
  logpush: true,
959
+ placement: {
960
+ mode: "smart",
961
+ },
958
962
  };
959
963
 
960
964
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -1030,6 +1034,9 @@ describe("normalizeAndValidateConfig()", () => {
1030
1034
  node_compat: "INVALID",
1031
1035
  first_party_worker: "INVALID",
1032
1036
  logpush: "INVALID",
1037
+ placement: {
1038
+ mode: "INVALID",
1039
+ },
1033
1040
  } as unknown as RawEnvironment;
1034
1041
 
1035
1042
  const { config, diagnostics } = normalizeAndValidateConfig(
@@ -1093,6 +1100,7 @@ describe("normalizeAndValidateConfig()", () => {
1093
1100
  - Expected \\"name\\" to be of type string, alphanumeric and lowercase with dashes only but got 111.
1094
1101
  - Expected \\"main\\" to be of type string but got 1333.
1095
1102
  - Expected \\"usage_model\\" field to be one of [\\"bundled\\",\\"unbound\\"] but got \\"INVALID\\".
1103
+ - Expected \\"placement.mode\\" field to be one of [\\"off\\",\\"smart\\"] but got \\"INVALID\\".
1096
1104
  - The field \\"define.DEF1\\" should be a string but got 1777.
1097
1105
  - Expected \\"no_bundle\\" to be of type boolean but got \\"INVALID\\".
1098
1106
  - Expected \\"minify\\" to be of type boolean but got \\"INVALID\\".
@@ -0,0 +1,371 @@
1
+ import * as fs from "node:fs";
2
+ import { rest } from "msw";
3
+ import { endEventLoop } from "./helpers/end-event-loop";
4
+ import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
5
+ import { mockConsoleMethods } from "./helpers/mock-console";
6
+ import { clearDialogs, mockConfirm } from "./helpers/mock-dialogs";
7
+ import { useMockIsTTY } from "./helpers/mock-istty";
8
+ import { createFetchResult, msw } from "./helpers/msw";
9
+ import { runInTempDir } from "./helpers/run-in-tmp";
10
+ import { runWrangler } from "./helpers/run-wrangler";
11
+
12
+ describe("constellation help", () => {
13
+ const std = mockConsoleMethods();
14
+ runInTempDir();
15
+
16
+ it("should show help when no argument is passed", async () => {
17
+ await runWrangler("constellation");
18
+ await endEventLoop();
19
+
20
+ expect(std.out).toMatchInlineSnapshot(`
21
+ "wrangler constellation
22
+
23
+ 🤖 Interact with Constellation AI models
24
+
25
+ Commands:
26
+ wrangler constellation project Manage your projects
27
+ wrangler constellation model Manage your models
28
+ wrangler constellation catalog Check the curated model catalog
29
+ wrangler constellation runtime Check the suported runtimes
30
+
31
+ Flags:
32
+ -j, --experimental-json-config Experimental: Support wrangler.json [boolean]
33
+ -c, --config Path to .toml configuration file [string]
34
+ -e, --env Environment to use for operations and .env files [string]
35
+ -h, --help Show help [boolean]
36
+ -v, --version Show version number [boolean]"
37
+ `);
38
+ });
39
+
40
+ it("should show help when an invalid argument is passed", async () => {
41
+ await expect(() => runWrangler("constellation asdf")).rejects.toThrow(
42
+ "Unknown argument: asdf"
43
+ );
44
+
45
+ expect(std.err).toMatchInlineSnapshot(`
46
+ "X [ERROR] Unknown argument: asdf
47
+
48
+ "
49
+ `);
50
+ expect(std.out).toMatchInlineSnapshot(`
51
+ "
52
+ wrangler constellation
53
+
54
+ 🤖 Interact with Constellation AI models
55
+
56
+ Commands:
57
+ wrangler constellation project Manage your projects
58
+ wrangler constellation model Manage your models
59
+ wrangler constellation catalog Check the curated model catalog
60
+ wrangler constellation runtime Check the suported runtimes
61
+
62
+ Flags:
63
+ -j, --experimental-json-config Experimental: Support wrangler.json [boolean]
64
+ -c, --config Path to .toml configuration file [string]
65
+ -e, --env Environment to use for operations and .env files [string]
66
+ -h, --help Show help [boolean]
67
+ -v, --version Show version number [boolean]"
68
+ `);
69
+ });
70
+ });
71
+
72
+ describe("constellation commands", () => {
73
+ mockAccountId();
74
+ mockApiToken();
75
+ runInTempDir();
76
+ const { setIsTTY } = useMockIsTTY();
77
+
78
+ const std = mockConsoleMethods();
79
+
80
+ beforeEach(() => {
81
+ // @ts-expect-error we're using a very simple setTimeout mock here
82
+ jest.spyOn(global, "setTimeout").mockImplementation((fn, _period) => {
83
+ setImmediate(fn);
84
+ });
85
+ setIsTTY(true);
86
+ });
87
+
88
+ afterEach(() => {
89
+ clearDialogs();
90
+ });
91
+
92
+ it("should handle project creation", async () => {
93
+ mockConstellationRequest();
94
+ await runWrangler("constellation project create new_project ONNX");
95
+ expect(std.out).toMatchInlineSnapshot(`
96
+ "--------------------
97
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
98
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
99
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
100
+ --------------------
101
+
102
+ ✅ Successfully created Project \\"new_project3\\"!"
103
+ `);
104
+ });
105
+
106
+ it("should handle project listing", async () => {
107
+ mockConstellationRequest();
108
+ await runWrangler("constellation project list");
109
+ expect(std.out).toMatchInlineSnapshot(`
110
+ "--------------------
111
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
112
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
113
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
114
+ --------------------
115
+
116
+ ┌──────────────────────────────────────┬──────────────┬─────────┬─────────────────────────────┐
117
+ │ id │ name │ runtime │ created_at │
118
+ ├──────────────────────────────────────┼──────────────┼─────────┼─────────────────────────────┤
119
+ │ 4806cdcf-9aa7-4fa2-b6a1-77fe9e196680 │ new_project3 │ ONNX │ 2023-04-28T13:25:58.513105Z │
120
+ └──────────────────────────────────────┴──────────────┴─────────┴─────────────────────────────┘"
121
+ `);
122
+ });
123
+
124
+ it("should handle project deletion", async () => {
125
+ mockConstellationRequest();
126
+ mockConfirm({
127
+ text: "Ok to proceed?",
128
+ result: true,
129
+ });
130
+
131
+ await runWrangler("constellation project delete new_project3");
132
+ expect(std.out).toMatchInlineSnapshot(`
133
+ "--------------------
134
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
135
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
136
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
137
+ --------------------
138
+
139
+ About to delete Project 'new_project3' (4806cdcf-9aa7-4fa2-b6a1-77fe9e196680).
140
+ Deleting...
141
+ Deleted 'new_project3' successfully."
142
+ `);
143
+ });
144
+
145
+ it("should handle catalog list", async () => {
146
+ mockConstellationRequest();
147
+ await runWrangler("constellation catalog list");
148
+ expect(std.out).toMatchInlineSnapshot(`
149
+ "--------------------
150
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
151
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
152
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
153
+ --------------------
154
+
155
+ ┌──────────────────────────────────────┬──────────────────────┬─────────────────┬───────────────┐
156
+ │ project_id │ project_name │ project_runtime │ models │
157
+ ├──────────────────────────────────────┼──────────────────────┼─────────────────┼───────────────┤
158
+ │ b162a29d-0a6d-4155-bedf-54a01fc8d0ef │ image-classification │ ONNX │ squeezenet1_1 │
159
+ └──────────────────────────────────────┴──────────────────────┴─────────────────┴───────────────┘"
160
+ `);
161
+ });
162
+
163
+ it("should handle runtime list", async () => {
164
+ mockConstellationRequest();
165
+ await runWrangler("constellation runtime list");
166
+ expect(std.out).toMatchInlineSnapshot(`
167
+ "--------------------
168
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
169
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
170
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
171
+ --------------------
172
+
173
+ ┌─────────┐
174
+ │ name │
175
+ ├─────────┤
176
+ │ ONNX │
177
+ ├─────────┤
178
+ │ XGBoost │
179
+ └─────────┘"
180
+ `);
181
+ });
182
+
183
+ it("should handle model upload", async () => {
184
+ mockConstellationRequest();
185
+ await fs.promises.writeFile("model.onnx", `model`);
186
+ await runWrangler(
187
+ "constellation model upload new_project3 model2 model.onnx"
188
+ );
189
+ expect(std.out).toMatchInlineSnapshot(`
190
+ "--------------------
191
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
192
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
193
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
194
+ --------------------
195
+
196
+ ✅ Successfully uploaded Model \\"model2\\"!"
197
+ `);
198
+ });
199
+
200
+ it("should handle model list", async () => {
201
+ mockConstellationRequest();
202
+ await runWrangler("constellation model list new_project3");
203
+ expect(std.out).toMatchInlineSnapshot(`
204
+ "--------------------
205
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
206
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
207
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
208
+ --------------------
209
+
210
+ ┌──────────────────────────────────────┬──────────────────────────────────────┬────────┬─────────────┬─────────────────────────────┐
211
+ │ id │ project_id │ name │ description │ created_at │
212
+ ├──────────────────────────────────────┼──────────────────────────────────────┼────────┼─────────────┼─────────────────────────────┤
213
+ │ 450bb086-3c09-4991-a0cc-eed48c504ae0 │ 9d478427-dea6-4988-9b16-f6f8888d974c │ model1 │ │ 2023-04-28T11:15:14.806217Z │
214
+ ├──────────────────────────────────────┼──────────────────────────────────────┼────────┼─────────────┼─────────────────────────────┤
215
+ │ 2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02 │ 9d478427-dea6-4988-9b16-f6f8888d974c │ model2 │ │ 2023-04-28T13:50:37.494090Z │
216
+ └──────────────────────────────────────┴──────────────────────────────────────┴────────┴─────────────┴─────────────────────────────┘"
217
+ `);
218
+ });
219
+
220
+ it("should handle model deletion", async () => {
221
+ mockConstellationRequest();
222
+ mockConfirm({
223
+ text: "Ok to proceed?",
224
+ result: true,
225
+ });
226
+
227
+ await runWrangler("constellation model delete new_project3 model2");
228
+ expect(std.out).toMatchInlineSnapshot(`
229
+ "--------------------
230
+ 🚧 Constellation AI is currently in open alpha and is not recommended for production data and traffic
231
+ 🚧 Please report any bugs to https://github.com/cloudflare/workers-sdk/issues/new/choose
232
+ 🚧 To give feedback, visit https://discord.gg/cloudflaredev
233
+ --------------------
234
+
235
+ About to delete Model 'model2' (2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02).
236
+ Deleting...
237
+ Deleted 'model2' successfully."
238
+ `);
239
+ });
240
+ });
241
+
242
+ /** Create a mock handler for Constellation API */
243
+ function mockConstellationRequest() {
244
+ msw.use(
245
+ rest.get("*/accounts/:accountId/constellation/project", (req, res, ctx) => {
246
+ return res.once(
247
+ ctx.json(
248
+ createFetchResult(
249
+ [
250
+ {
251
+ id: "4806cdcf-9aa7-4fa2-b6a1-77fe9e196680",
252
+ name: "new_project3",
253
+ runtime: "ONNX",
254
+ created_at: "2023-04-28T13:25:58.513105Z",
255
+ },
256
+ ],
257
+ true
258
+ )
259
+ )
260
+ );
261
+ }),
262
+ rest.post(
263
+ "*/accounts/:accountId/constellation/project",
264
+ (req, res, ctx) => {
265
+ return res.once(
266
+ ctx.json(
267
+ createFetchResult(
268
+ {
269
+ id: "4806cdcf-9aa7-4fa2-b6a1-77fe9e196680",
270
+ name: "new_project3",
271
+ runtime: "ONNX",
272
+ created_at: "2023-04-28T13:25:58.513105Z",
273
+ },
274
+ true
275
+ )
276
+ )
277
+ );
278
+ }
279
+ ),
280
+ rest.delete(
281
+ "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680",
282
+ (req, res, ctx) => {
283
+ return res.once(ctx.json(createFetchResult(null, true)));
284
+ }
285
+ ),
286
+ rest.get("*/accounts/:accountId/constellation/catalog", (req, res, ctx) => {
287
+ return res.once(
288
+ ctx.json(
289
+ createFetchResult(
290
+ [
291
+ {
292
+ project: {
293
+ id: "b162a29d-0a6d-4155-bedf-54a01fc8d0ef",
294
+ name: "image-classification",
295
+ runtime: "ONNX",
296
+ created_at: "2023-04-27T18:55:38.417187Z",
297
+ },
298
+ models: [
299
+ {
300
+ id: "edb202d3-f4ac-43ab-8762-3ae6b43c4c57",
301
+ project_id: "b162a29d-0a6d-4155-bedf-54a01fc8d0ef",
302
+ name: "squeezenet1_1",
303
+ description: null,
304
+ created_at: "2023-04-27T18:56:15.305087Z",
305
+ },
306
+ ],
307
+ },
308
+ ],
309
+ true
310
+ )
311
+ )
312
+ );
313
+ }),
314
+ rest.get("*/accounts/:accountId/constellation/runtime", (req, res, ctx) => {
315
+ return res.once(ctx.json(createFetchResult(["ONNX", "XGBoost"], true)));
316
+ }),
317
+ rest.post(
318
+ "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680/model",
319
+ (req, res, ctx) => {
320
+ return res.once(
321
+ ctx.json(
322
+ createFetchResult(
323
+ {
324
+ id: "2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02",
325
+ project_id: "4806cdcf-9aa7-4fa2-b6a1-77fe9e196680",
326
+ name: "model2",
327
+ description: null,
328
+ created_at: "2023-04-28T13:50:37.494090Z",
329
+ },
330
+ true
331
+ )
332
+ )
333
+ );
334
+ }
335
+ ),
336
+ rest.get(
337
+ "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680/model",
338
+ (req, res, ctx) => {
339
+ return res.once(
340
+ ctx.json(
341
+ createFetchResult(
342
+ [
343
+ {
344
+ id: "450bb086-3c09-4991-a0cc-eed48c504ae0",
345
+ project_id: "9d478427-dea6-4988-9b16-f6f8888d974c",
346
+ name: "model1",
347
+ description: null,
348
+ created_at: "2023-04-28T11:15:14.806217Z",
349
+ },
350
+ {
351
+ id: "2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02",
352
+ project_id: "9d478427-dea6-4988-9b16-f6f8888d974c",
353
+ name: "model2",
354
+ description: null,
355
+ created_at: "2023-04-28T13:50:37.494090Z",
356
+ },
357
+ ],
358
+ true
359
+ )
360
+ )
361
+ );
362
+ }
363
+ ),
364
+ rest.delete(
365
+ "*/accounts/:accountId/constellation/project/4806cdcf-9aa7-4fa2-b6a1-77fe9e196680/model/2dd35b4e-0c7a-4c7a-a9e2-e33c0e17bc02",
366
+ (req, res, ctx) => {
367
+ return res.once(ctx.json(createFetchResult(null, true)));
368
+ }
369
+ )
370
+ );
371
+ }
@@ -49,6 +49,7 @@ describe("wrangler", () => {
49
49
  wrangler r2 📦 Interact with an R2 store
50
50
  wrangler dispatch-namespace 📦 Interact with a dispatch namespace
51
51
  wrangler d1 🗄 Interact with a D1 database
52
+ wrangler constellation 🤖 Interact with Constellation AI models
52
53
  wrangler pubsub 📮 Interact and manage Pub/Sub Brokers
53
54
  wrangler mtls-certificate 🪪 Manage certificates used for mTLS connections
54
55
  wrangler login 🔓 Login to Cloudflare
@@ -102,6 +103,7 @@ describe("wrangler", () => {
102
103
  wrangler r2 📦 Interact with an R2 store
103
104
  wrangler dispatch-namespace 📦 Interact with a dispatch namespace
104
105
  wrangler d1 🗄 Interact with a D1 database
106
+ wrangler constellation 🤖 Interact with Constellation AI models
105
107
  wrangler pubsub 📮 Interact and manage Pub/Sub Brokers
106
108
  wrangler mtls-certificate 🪪 Manage certificates used for mTLS connections
107
109
  wrangler login 🔓 Login to Cloudflare
@@ -379,6 +379,7 @@ describe("wrangler", () => {
379
379
  wrangler r2 📦 Interact with an R2 store
380
380
  wrangler dispatch-namespace 📦 Interact with a dispatch namespace
381
381
  wrangler d1 🗄 Interact with a D1 database
382
+ wrangler constellation 🤖 Interact with Constellation AI models
382
383
  wrangler pubsub 📮 Interact and manage Pub/Sub Brokers
383
384
  wrangler mtls-certificate 🪪 Manage certificates used for mTLS connections
384
385
  wrangler login 🔓 Login to Cloudflare
@@ -448,5 +448,81 @@ export default {
448
448
  "Build failed with 1 error:
449
449
  hello.js:2:36: ERROR: Could not resolve \\"node:async_hooks\\""
450
450
  `);
451
+ expect(std.err).toContain(
452
+ 'The package "node:async_hooks" wasn\'t found on the file system but is built into node.'
453
+ );
454
+ expect(std.err).toContain(
455
+ 'Add the "nodejs_compat" compatibility flag to your Pages project to enable Node.js compatibility.'
456
+ );
457
+ });
458
+
459
+ it("should compile a _worker.js/ directory", async () => {
460
+ mkdirSync("public");
461
+ mkdirSync("public/_worker.js");
462
+ writeFileSync(
463
+ "public/_worker.js/index.js",
464
+ `
465
+ import { cat } from "./cat.js";
466
+
467
+ export default {
468
+ async fetch(request, env) {
469
+ return new Response("Hello from _worker.js/index.js" + cat);
470
+ },
471
+ };`
472
+ );
473
+ writeFileSync(
474
+ "public/_worker.js/cat.js",
475
+ `
476
+ export const cat = "cat";`
477
+ );
478
+
479
+ await runWrangler(`pages functions build --outfile=public/_worker.bundle`);
480
+
481
+ expect(existsSync("public/_worker.bundle")).toBe(true);
482
+ expect(std.out).toMatchInlineSnapshot(`
483
+ "🚧 'wrangler pages <command>' is a beta command. Please report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose
484
+ ✨ Compiled Worker successfully"
485
+ `);
486
+
487
+ const workerBundleContents = readFileSync("public/_worker.bundle", "utf-8");
488
+ const workerBundleWithConstantData = replaceRandomWithConstantData(
489
+ workerBundleContents,
490
+ [
491
+ [/------formdata-undici-0.[0-9]*/g, "------formdata-undici-0.test"],
492
+ [/bundledWorker-0.[0-9]*.mjs/g, "bundledWorker-0.test.mjs"],
493
+ [/bundledWorker-0.[0-9]*.map/g, "bundledWorker-0.test.map"],
494
+ ]
495
+ );
496
+
497
+ expect(workerBundleWithConstantData).toMatchInlineSnapshot(`
498
+ "------formdata-undici-0.test
499
+ Content-Disposition: form-data; name=\\"metadata\\"
500
+
501
+ {\\"main_module\\":\\"bundledWorker-0.test.mjs\\"}
502
+ ------formdata-undici-0.test
503
+ Content-Disposition: form-data; name=\\"bundledWorker-0.test.mjs\\"; filename=\\"bundledWorker-0.test.mjs\\"
504
+ Content-Type: application/javascript+module
505
+
506
+ import { cat } from \\"./cat.js\\";
507
+ var worker_default = {
508
+ async fetch(request, env) {
509
+ return new Response(\\"Hello from _worker.js/index.js\\" + cat);
510
+ }
511
+ };
512
+ export {
513
+ worker_default as default
514
+ };
515
+ //# sourceMappingURL=bundledWorker-0.test.mjs.map
516
+
517
+ ------formdata-undici-0.test
518
+ Content-Disposition: form-data; name=\\"cat.js\\"; filename=\\"cat.js\\"
519
+ Content-Type: application/javascript+module
520
+
521
+
522
+ export const cat = \\"cat\\";
523
+ ------formdata-undici-0.test--"
524
+ `);
525
+
526
+ expect(std.err).toMatchInlineSnapshot(`""`);
451
527
  });
452
528
  });
@@ -13,6 +13,7 @@ import type {
13
13
  ScheduledEvent,
14
14
  AlarmEvent,
15
15
  EmailEvent,
16
+ TailInfo,
16
17
  } from "../tail/createTail";
17
18
  import type { RequestInit } from "undici";
18
19
  import type WebSocket from "ws";
@@ -655,6 +656,7 @@ function isRequest(
655
656
  | RequestEvent
656
657
  | AlarmEvent
657
658
  | EmailEvent
659
+ | TailInfo
658
660
  | undefined
659
661
  | null
660
662
  ): event is RequestEvent {
@@ -140,7 +140,7 @@ describe("publish", () => {
140
140
 
141
141
  expect(std.out).toMatchInlineSnapshot(`
142
142
  "Attempting to login via OAuth...
143
- Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
143
+ Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
144
144
  Successfully logged in.
145
145
  Total Upload: xx KiB / gzip: xx KiB
146
146
  Uploaded test-name (TIMINGS)
@@ -180,7 +180,7 @@ describe("publish", () => {
180
180
 
181
181
  expect(std.out).toMatchInlineSnapshot(`
182
182
  "Attempting to login via OAuth...
183
- Opening a link in your default browser: https://dash.staging.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
183
+ Opening a link in your default browser: https://dash.staging.cloudflare.com/oauth2/auth?response_type=code&client_id=54d11594-84e4-41aa-b438-e81b8fa78ee7&redirect_uri=http%3A%2F%2Flocalhost%3A8976%2Foauth%2Fcallback&scope=account%3Aread%20user%3Aread%20workers%3Awrite%20workers_kv%3Awrite%20workers_routes%3Awrite%20workers_scripts%3Awrite%20workers_tail%3Aread%20d1%3Awrite%20pages%3Awrite%20zone%3Aread%20ssl_certs%3Awrite%20constellation%3Awrite%20offline_access&state=MOCK_STATE_PARAM&code_challenge=MOCK_CODE_CHALLENGE&code_challenge_method=S256
184
184
  Successfully logged in.
185
185
  Total Upload: xx KiB / gzip: xx KiB
186
186
  Uploaded test-name (TIMINGS)
@@ -7224,7 +7224,7 @@ export default{
7224
7224
  expect(
7225
7225
  esbuild.formatMessagesSync(err?.errors ?? [], { kind: "error" }).join()
7226
7226
  ).toMatch(
7227
- /The package "path" wasn't found on the file system but is built into node\.\s+Add "node_compat = true" to your wrangler\.toml file to enable Node compatibility\./
7227
+ /The package "path" wasn't found on the file system but is built into node\.\s+Add "node_compat = true" to your wrangler\.toml file to enable Node.js compatibility\./
7228
7228
  );
7229
7229
  });
7230
7230
 
@@ -14,6 +14,7 @@ import type {
14
14
  ScheduledEvent,
15
15
  AlarmEvent,
16
16
  EmailEvent,
17
+ TailInfo,
17
18
  } from "../tail/createTail";
18
19
  import type { RequestInit } from "undici";
19
20
  import type WebSocket from "ws";
@@ -56,10 +57,10 @@ describe("tail", () => {
56
57
  await runWrangler("tail durable-object--websocket--response");
57
58
  expect(std.out).toMatchInlineSnapshot(`""`);
58
59
  expect(std.warn).toMatchInlineSnapshot(`
59
- "▲ [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.
60
61
 
61
- "
62
- `);
62
+ "
63
+ `);
63
64
  expect(std.err).toMatchInlineSnapshot(`""`);
64
65
  });
65
66
  it("creates and then delete tails", async () => {
@@ -503,10 +504,31 @@ describe("tail", () => {
503
504
  )
504
505
  .replace(mockTailExpiration.toISOString(), "[mock expiration date]")
505
506
  ).toMatchInlineSnapshot(`
506
- "Successfully created tail, expires at [mock expiration date]
507
- Connected to test-worker, waiting for logs...
508
- Email from:${mockEmailEventFrom} to:${mockEmailEventTo} size:${mockEmailEventSize} @ [mock event timestamp] - Ok"
509
- `);
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
+ const event = generateTailInfo();
518
+ const message = generateMockEventMessage({ event });
519
+ const serializedMessage = serialize(message);
520
+
521
+ api.ws.send(serializedMessage);
522
+ expect(
523
+ std.out.replace(
524
+ mockTailExpiration.toISOString(),
525
+ "[mock expiration date]"
526
+ )
527
+ ).toMatchInlineSnapshot(`
528
+ "Successfully created tail, expires at [mock expiration date]
529
+ Connected to test-worker, waiting for logs...
530
+ Tail is currently in sampling mode due to the high volume of messages. To prevent messages from being dropped consider adding filters."
531
+ `);
510
532
  });
511
533
 
512
534
  it("should not crash when the tail message has a void event", async () => {
@@ -675,6 +697,7 @@ function isRequest(
675
697
  | RequestEvent
676
698
  | AlarmEvent
677
699
  | EmailEvent
700
+ | TailInfo
678
701
  | undefined
679
702
  | null
680
703
  ): event is RequestEvent {
@@ -956,3 +979,11 @@ function generateMockEmailEvent(opts?: Partial<EmailEvent>): EmailEvent {
956
979
  rawSize: opts?.rawSize || mockEmailEventSize,
957
980
  };
958
981
  }
982
+
983
+ function generateTailInfo(): TailInfo {
984
+ return {
985
+ message:
986
+ "Tail is currently in sampling mode due to the high volume of messages. To prevent messages from being dropped consider adding filters.",
987
+ type: "overload",
988
+ };
989
+ }