wrangler 2.5.0 → 2.6.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.
@@ -1,9 +1,10 @@
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 } from "./helpers/msw";
7
8
  import { runInTempDir } from "./helpers/run-in-tmp";
8
9
  import { runWrangler } from "./helpers/run-wrangler";
9
10
  import type {
@@ -16,6 +17,11 @@ import type { RequestInit } from "undici";
16
17
  import type WebSocket from "ws";
17
18
 
18
19
  describe("pages deployment tail", () => {
20
+ runInTempDir();
21
+ mockAccountId();
22
+ mockApiToken();
23
+ const std = mockConsoleMethods();
24
+
19
25
  beforeAll(() => {
20
26
  // Force the CLI to be "non-interactive" in test env
21
27
  process.env.CF_PAGES = "1";
@@ -25,16 +31,9 @@ describe("pages deployment tail", () => {
25
31
  delete process.env.CF_PAGES;
26
32
  });
27
33
 
28
- runInTempDir();
29
- mockAccountId();
30
- mockApiToken();
31
-
32
- const std = mockConsoleMethods();
33
-
34
34
  afterEach(() => {
35
35
  mockWebSockets.forEach((ws) => ws.close());
36
36
  mockWebSockets.splice(0);
37
- unsetAllMocks();
38
37
  });
39
38
 
40
39
  /**
@@ -64,7 +63,7 @@ describe("pages deployment tail", () => {
64
63
  expect(api.requests.creation.length).toStrictEqual(1);
65
64
  expect(api.requests.deletion.count).toStrictEqual(0);
66
65
 
67
- api.ws.close();
66
+ await api.closeHelper();
68
67
  expect(api.requests.deletion.count).toStrictEqual(1);
69
68
  });
70
69
 
@@ -80,7 +79,7 @@ describe("pages deployment tail", () => {
80
79
  expect(api.requests.creation.length).toStrictEqual(1);
81
80
  expect(api.requests.deletion.count).toStrictEqual(0);
82
81
 
83
- api.ws.close();
82
+ await api.closeHelper();
84
83
  expect(api.requests.deletion.count).toStrictEqual(1);
85
84
  });
86
85
 
@@ -104,13 +103,13 @@ describe("pages deployment tail", () => {
104
103
  expect(api.requests.creation.length).toStrictEqual(1);
105
104
  expect(api.requests.deletion.count).toStrictEqual(0);
106
105
 
107
- api.ws.close();
106
+ await api.closeHelper();
108
107
  expect(api.requests.deletion.count).toStrictEqual(1);
109
108
  });
110
109
 
111
110
  it("errors when the websocket closes unexpectedly", async () => {
112
111
  const api = mockTailAPIs();
113
- api.ws.close();
112
+ await api.closeHelper();
114
113
 
115
114
  await expect(
116
115
  runWrangler(
@@ -134,24 +133,27 @@ describe("pages deployment tail", () => {
134
133
  });
135
134
 
136
135
  describe("filtering", () => {
137
- it("sends sampling rate filters", async () => {
138
- const api = mockTailAPIs();
136
+ it("should throw for bad sampling rate filters ranges", async () => {
139
137
  const tooHigh = runWrangler(
140
138
  "pages deployment tail mock-deployment-id --project-name mock-project --sampling-rate 10"
141
139
  );
140
+
142
141
  await expect(tooHigh).rejects.toThrow();
143
142
 
144
143
  const tooLow = runWrangler(
145
144
  "pages deployment tail mock-deployment-id --project-name mock-project --sampling-rate -5"
146
145
  );
147
146
  await expect(tooLow).rejects.toThrow();
147
+ });
148
148
 
149
+ it("should send sampling rate filter", async () => {
150
+ const api = mockTailAPIs();
149
151
  await runWrangler(
150
152
  "pages deployment tail mock-deployment-id --project-name mock-project --sampling-rate 0.25"
151
153
  );
152
- expect(api.requests.creation[0].body).toEqual(
153
- `{"filters":[{"sampling_rate":0.25}]}`
154
- );
154
+ expect(api.requests.creation[0]).toEqual({
155
+ filters: [{ sampling_rate: 0.25 }],
156
+ });
155
157
  });
156
158
 
157
159
  it("sends single status filters", async () => {
@@ -159,9 +161,13 @@ describe("pages deployment tail", () => {
159
161
  await runWrangler(
160
162
  "pages deployment tail mock-deployment-id --project-name mock-project --status error"
161
163
  );
162
- expect(api.requests.creation[0].body).toEqual(
163
- `{"filters":[{"outcome":["exception","exceededCpu","exceededMemory","unknown"]}]}`
164
- );
164
+ expect(api.requests.creation[0]).toEqual({
165
+ filters: [
166
+ {
167
+ outcome: ["exception", "exceededCpu", "exceededMemory", "unknown"],
168
+ },
169
+ ],
170
+ });
165
171
  });
166
172
 
167
173
  it("sends multiple status filters", async () => {
@@ -169,9 +175,19 @@ describe("pages deployment tail", () => {
169
175
  await runWrangler(
170
176
  "pages deployment tail mock-deployment-id --project-name mock-project --status error --status canceled"
171
177
  );
172
- expect(api.requests.creation[0].body).toEqual(
173
- `{"filters":[{"outcome":["exception","exceededCpu","exceededMemory","unknown","canceled"]}]}`
174
- );
178
+ expect(api.requests.creation[0]).toEqual({
179
+ filters: [
180
+ {
181
+ outcome: [
182
+ "exception",
183
+ "exceededCpu",
184
+ "exceededMemory",
185
+ "unknown",
186
+ "canceled",
187
+ ],
188
+ },
189
+ ],
190
+ });
175
191
  });
176
192
 
177
193
  it("sends single HTTP method filters", async () => {
@@ -179,9 +195,9 @@ describe("pages deployment tail", () => {
179
195
  await runWrangler(
180
196
  "pages deployment tail mock-deployment-id --project-name mock-project --method POST"
181
197
  );
182
- expect(api.requests.creation[0].body).toEqual(
183
- `{"filters":[{"method":["POST"]}]}`
184
- );
198
+ expect(api.requests.creation[0]).toEqual({
199
+ filters: [{ method: ["POST"] }],
200
+ });
185
201
  });
186
202
 
187
203
  it("sends multiple HTTP method filters", async () => {
@@ -189,9 +205,9 @@ describe("pages deployment tail", () => {
189
205
  await runWrangler(
190
206
  "pages deployment tail mock-deployment-id --project-name mock-project --method POST --method GET"
191
207
  );
192
- expect(api.requests.creation[0].body).toEqual(
193
- `{"filters":[{"method":["POST","GET"]}]}`
194
- );
208
+ expect(api.requests.creation[0]).toEqual({
209
+ filters: [{ method: ["POST", "GET"] }],
210
+ });
195
211
  });
196
212
 
197
213
  it("sends header filters without a query", async () => {
@@ -199,9 +215,9 @@ describe("pages deployment tail", () => {
199
215
  await runWrangler(
200
216
  "pages deployment tail mock-deployment-id --project-name mock-project --header X-CUSTOM-HEADER"
201
217
  );
202
- expect(api.requests.creation[0].body).toEqual(
203
- `{"filters":[{"header":{"key":"X-CUSTOM-HEADER"}}]}`
204
- );
218
+ expect(api.requests.creation[0]).toEqual({
219
+ filters: [{ header: { key: "X-CUSTOM-HEADER" } }],
220
+ });
205
221
  });
206
222
 
207
223
  it("sends header filters with a query", async () => {
@@ -209,9 +225,9 @@ describe("pages deployment tail", () => {
209
225
  await runWrangler(
210
226
  "pages deployment tail mock-deployment-id --project-name mock-project --header X-CUSTOM-HEADER:some-value"
211
227
  );
212
- expect(api.requests.creation[0].body).toEqual(
213
- `{"filters":[{"header":{"key":"X-CUSTOM-HEADER","query":"some-value"}}]}`
214
- );
228
+ expect(api.requests.creation[0]).toEqual({
229
+ filters: [{ header: { key: "X-CUSTOM-HEADER", query: "some-value" } }],
230
+ });
215
231
  });
216
232
 
217
233
  it("sends single IP filters", async () => {
@@ -221,9 +237,9 @@ describe("pages deployment tail", () => {
221
237
  await runWrangler(
222
238
  `pages deployment tail mock-deployment-id --project-name mock-project --ip ${fakeIp}`
223
239
  );
224
- expect(api.requests.creation[0].body).toEqual(
225
- `{"filters":[{"client_ip":["${fakeIp}"]}]}`
226
- );
240
+ expect(api.requests.creation[0]).toEqual({
241
+ filters: [{ client_ip: [`${fakeIp}`] }],
242
+ });
227
243
  });
228
244
 
229
245
  it("sends multiple IP filters", async () => {
@@ -233,9 +249,9 @@ describe("pages deployment tail", () => {
233
249
  await runWrangler(
234
250
  `pages deployment tail mock-deployment-id --project-name mock-project --ip ${fakeIp} --ip self`
235
251
  );
236
- expect(api.requests.creation[0].body).toEqual(
237
- `{"filters":[{"client_ip":["${fakeIp}","self"]}]}`
238
- );
252
+ expect(api.requests.creation[0]).toEqual({
253
+ filters: [{ client_ip: [`${fakeIp}`, "self"] }],
254
+ });
239
255
  });
240
256
 
241
257
  it("sends search filters", async () => {
@@ -245,9 +261,9 @@ describe("pages deployment tail", () => {
245
261
  await runWrangler(
246
262
  `pages deployment tail mock-deployment-id --project-name mock-project --search ${search}`
247
263
  );
248
- expect(api.requests.creation[0].body).toEqual(
249
- `{"filters":[{"query":"${search}"}]}`
250
- );
264
+ expect(api.requests.creation[0]).toEqual({
265
+ filters: [{ query: `${search}` }],
266
+ });
251
267
  });
252
268
 
253
269
  it("sends everything but the kitchen sink", async () => {
@@ -268,12 +284,29 @@ describe("pages deployment tail", () => {
268
284
  `--search ${query} ` +
269
285
  `--debug`;
270
286
 
271
- 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"}]}`;
287
+ const expectedWebsocketMessage = {
288
+ filters: [
289
+ { sampling_rate: 0.69 },
290
+ {
291
+ outcome: [
292
+ "ok",
293
+ "exception",
294
+ "exceededCpu",
295
+ "exceededMemory",
296
+ "unknown",
297
+ ],
298
+ },
299
+ { method: ["GET", "POST", "PUT"] },
300
+ { header: { key: "X-HELLO", query: "world" } },
301
+ { client_ip: ["192.0.2.1", "self"] },
302
+ { query: "onlyTheseMessagesPlease" },
303
+ ],
304
+ };
272
305
 
273
306
  await runWrangler(
274
307
  `pages deployment tail mock-deployment-id --project-name mock-project ${cliFilters}`
275
308
  );
276
- expect(api.requests.creation[0].body).toEqual(expectedWebsocketMessage);
309
+ expect(api.requests.creation[0]).toEqual(expectedWebsocketMessage);
277
310
  });
278
311
  });
279
312
 
@@ -476,6 +509,7 @@ describe("pages deployment tail", () => {
476
509
  it("logs console messages and exceptions", async () => {
477
510
  setIsTTY(true);
478
511
  const api = mockTailAPIs();
512
+
479
513
  await runWrangler(
480
514
  "pages deployment tail mock-deployment-id --project-name mock-project"
481
515
  );
@@ -500,16 +534,12 @@ describe("pages deployment tail", () => {
500
534
  const serializedMessage = serialize(message);
501
535
 
502
536
  api.ws.send(serializedMessage);
537
+
503
538
  expect(
504
- std.out
505
- .replace(
506
- new Date(mockEventTimestamp).toLocaleString(),
507
- "[mock event timestamp]"
508
- )
509
- .replace(
510
- mockTailExpiration.toLocaleString(),
511
- "[mock expiration date]"
512
- )
539
+ std.out.replace(
540
+ new Date(mockEventTimestamp).toLocaleString(),
541
+ "[mock event timestamp]"
542
+ )
513
543
  ).toMatchInlineSnapshot(`
514
544
  "Connected to deployment mock-deployment-id, waiting for logs...
515
545
  GET https://example.org/ - Ok @ [mock event timestamp]
@@ -607,6 +637,7 @@ type MockAPI = {
607
637
  };
608
638
  ws: MockWebSocket;
609
639
  nextMessageJson(): Promise<unknown>;
640
+ closeHelper: () => Promise<void>;
610
641
  };
611
642
 
612
643
  /**
@@ -616,31 +647,40 @@ type MockAPI = {
616
647
  */
617
648
  function mockListDeployments(): RequestCounter {
618
649
  const requests: RequestCounter = { count: 0 };
619
- setMockResponse(
620
- `/accounts/:accountId/pages/projects/:projectName/deployments`,
621
- "GET",
622
- ([_url, _accountId, _projectName, _deploymentId], _req) => {
623
- requests.count++;
624
- return [
625
- {
626
- id: "mock-deployment-id",
627
- url: "https://87bbc8fe.mock.pages.dev",
628
- environment: "production",
629
- created_on: "2021-11-17T14:52:26.133835Z",
630
- latest_stage: {
631
- ended_on: "2021-11-17T14:52:26.133835Z",
632
- status: "success",
633
- },
634
- deployment_trigger: {
635
- metadata: {
636
- branch: "main",
637
- commit_hash: "c7649364c4cb32ad4f65b530b9424e8be5bec9d6",
638
- },
639
- },
640
- project_name: "mock-project",
641
- },
642
- ];
643
- }
650
+ msw.use(
651
+ rest.get(
652
+ `*/accounts/:accountId/pages/projects/:projectName/deployments`,
653
+ (_, res, ctx) => {
654
+ requests.count++;
655
+ return res.once(
656
+ ctx.status(200),
657
+ ctx.json({
658
+ success: true,
659
+ errors: [],
660
+ messages: [],
661
+ result: [
662
+ {
663
+ id: "mock-deployment-id",
664
+ url: "https://87bbc8fe.mock.pages.dev",
665
+ environment: "production",
666
+ created_on: "2021-11-17T14:52:26.133835Z",
667
+ latest_stage: {
668
+ ended_on: "2021-11-17T14:52:26.133835Z",
669
+ status: "success",
670
+ },
671
+ deployment_trigger: {
672
+ metadata: {
673
+ branch: "main",
674
+ commit_hash: "c7649364c4cb32ad4f65b530b9424e8be5bec9d6",
675
+ },
676
+ },
677
+ project_name: "mock-project",
678
+ },
679
+ ],
680
+ })
681
+ );
682
+ }
683
+ )
644
684
  );
645
685
 
646
686
  return requests;
@@ -662,17 +702,26 @@ type RequestCounter = {
662
702
  */
663
703
  function mockCreateTailRequest(): RequestInit[] {
664
704
  const requests: RequestInit[] = [];
665
- setMockResponse(
666
- `/accounts/:accountId/pages/projects/:projectName/deployments/:deploymentId/tails`,
667
- "POST",
668
- ([_url, _accountId, _projectName, _deploymentId], req) => {
669
- requests.push(req);
670
- return {
671
- id: "tail-id",
672
- url: websocketURL,
673
- expires_at: mockTailExpiration,
674
- };
675
- }
705
+ msw.use(
706
+ rest.post(
707
+ `*/accounts/:accountId/pages/projects/:projectName/deployments/:deploymentId/tails`,
708
+ async (req, res, ctx) => {
709
+ requests.push(await req.json());
710
+ return res.once(
711
+ ctx.status(200),
712
+ ctx.json({
713
+ success: true,
714
+ errors: [],
715
+ messages: [],
716
+ result: {
717
+ id: "tail-id",
718
+ url: websocketURL,
719
+ expires_at: mockTailExpiration,
720
+ },
721
+ })
722
+ );
723
+ }
724
+ )
676
725
  );
677
726
 
678
727
  return requests;
@@ -700,13 +749,17 @@ const mockEventScheduledTime = new Date(mockEventTimestamp).toISOString();
700
749
  */
701
750
  function mockDeleteTailRequest(): RequestCounter {
702
751
  const requests = { count: 0 };
703
- setMockResponse(
704
- `/accounts/:accountId/pages/projects/:projectName/deployments/:deploymentId/tails/:tailId`,
705
- "DELETE",
706
- ([_url, _accountId, _projectName, _deploymentId], _req) => {
707
- requests.count++;
708
- return null;
709
- }
752
+ msw.use(
753
+ rest.delete(
754
+ `*/accounts/:accountId/pages/projects/:projectName/deployments/:deploymentId/tails/:tailId`,
755
+ (_, res, ctx) => {
756
+ requests.count++;
757
+ return res.once(
758
+ ctx.status(200),
759
+ ctx.json({ success: true, errors: [], messages: [], result: null })
760
+ );
761
+ }
762
+ )
710
763
  );
711
764
 
712
765
  return requests;
@@ -730,7 +783,7 @@ function mockTailAPIs(): MockAPI {
730
783
  deployments: { count: 0 },
731
784
  },
732
785
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
733
- ws: null!, // will be set in the `beforeEach()` below.
786
+ ws: null!, // will be set in the `beforeEach()`.
734
787
 
735
788
  /**
736
789
  * Parse the next message received by the mock websocket as JSON
@@ -740,12 +793,23 @@ function mockTailAPIs(): MockAPI {
740
793
  const message = await api.ws.nextMessage;
741
794
  return JSON.parse(message as string);
742
795
  },
796
+ /**
797
+ * Close the mock websocket and clean up the API.
798
+ * The setTimeout forces a cycle to allow for closing and cleanup
799
+ * @returns a Promise that resolves when the websocket is closed
800
+ */
801
+ async closeHelper() {
802
+ api.ws.close();
803
+ await new Promise((resolve) => setTimeout(resolve, 0));
804
+ },
743
805
  };
806
+
807
+ api.ws = new MockWebSocket(websocketURL);
808
+ mockWebSockets.push(api.ws);
809
+
744
810
  api.requests.creation = mockCreateTailRequest();
745
811
  api.requests.deletion = mockDeleteTailRequest();
746
812
  api.requests.deployments = mockListDeployments();
747
- api.ws = new MockWebSocket(websocketURL);
748
- mockWebSockets.push(api.ws);
749
813
 
750
814
  return api;
751
815
  }
@@ -4497,6 +4497,10 @@ addEventListener('fetch', event => {});`
4497
4497
  { binding: "R2_BUCKET_ONE", bucket_name: "r2-bucket-one-name" },
4498
4498
  { binding: "R2_BUCKET_TWO", bucket_name: "r2-bucket-two-name" },
4499
4499
  ],
4500
+ analytics_engine_datasets: [
4501
+ { binding: "AE_DATASET_ONE", dataset: "ae-dataset-one-name" },
4502
+ { binding: "AE_DATASET_TWO", dataset: "ae-dataset-two-name" },
4503
+ ],
4500
4504
  text_blobs: {
4501
4505
  TEXT_BLOB_ONE: "./my-entire-app-depends-on-this.cfg",
4502
4506
  TEXT_BLOB_TWO: "./the-entirety-of-human-knowledge.txt",
@@ -4598,6 +4602,16 @@ addEventListener('fetch', event => {});`
4598
4602
  name: "R2_BUCKET_TWO",
4599
4603
  type: "r2_bucket",
4600
4604
  },
4605
+ {
4606
+ dataset: "ae-dataset-one-name",
4607
+ name: "AE_DATASET_ONE",
4608
+ type: "analytics_engine",
4609
+ },
4610
+ {
4611
+ dataset: "ae-dataset-two-name",
4612
+ name: "AE_DATASET_TWO",
4613
+ type: "analytics_engine",
4614
+ },
4601
4615
  {
4602
4616
  name: "httplogs",
4603
4617
  type: "logfwdr",
@@ -4656,6 +4670,9 @@ addEventListener('fetch', event => {});`
4656
4670
  - logfwdr:
4657
4671
  - httplogs: httplogs
4658
4672
  - trace: trace
4673
+ - Analytics Engine Datasets:
4674
+ - AE_DATASET_ONE: ae-dataset-one-name
4675
+ - AE_DATASET_TWO: ae-dataset-two-name
4659
4676
  - Text Blobs:
4660
4677
  - TEXT_BLOB_ONE: my-entire-app-depends-on-this.cfg
4661
4678
  - TEXT_BLOB_TWO: the-entirety-of-human-knowledge.txt
@@ -4713,6 +4730,12 @@ addEventListener('fetch', event => {});`
4713
4730
  bucket_name: "r2-bucket-two-name",
4714
4731
  },
4715
4732
  ],
4733
+ analytics_engine_datasets: [
4734
+ {
4735
+ binding: "CONFLICTING_NAME_FOUR",
4736
+ dataset: "analytics-engine-dataset-name",
4737
+ },
4738
+ ],
4716
4739
  text_blobs: {
4717
4740
  CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
4718
4741
  CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
@@ -4760,7 +4783,7 @@ addEventListener('fetch', event => {});`
4760
4783
  - CONFLICTING_NAME_ONE assigned to Durable Object, KV Namespace, and R2 Bucket bindings.
4761
4784
  - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
4762
4785
  - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
4763
- - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
4786
+ - CONFLICTING_NAME_FOUR assigned to Analytics Engine Dataset, Text Blob, and Unsafe bindings.
4764
4787
  - Bindings must have unique names, so that they can all be referenced in the worker.
4765
4788
  Please change your bindings to have unique names.]
4766
4789
  `);
@@ -4775,7 +4798,7 @@ addEventListener('fetch', event => {});`
4775
4798
  - CONFLICTING_NAME_TWO assigned to Durable Object and KV Namespace bindings.
4776
4799
  - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM
4777
4800
  Module, and Data Blob bindings.
4778
- - CONFLICTING_NAME_FOUR assigned to Text Blob and Unsafe bindings.
4801
+ - CONFLICTING_NAME_FOUR assigned to Analytics Engine Dataset, Text Blob, and Unsafe bindings.
4779
4802
  - Bindings must have unique names, so that they can all be referenced in the worker.
4780
4803
  Please change your bindings to have unique names.
4781
4804
 
@@ -4820,6 +4843,16 @@ addEventListener('fetch', event => {});`
4820
4843
  bucket_name: "r2-bucket-two-name",
4821
4844
  },
4822
4845
  ],
4846
+ analytics_engine_datasets: [
4847
+ {
4848
+ binding: "CONFLICTING_AE_DATASET_NAME",
4849
+ dataset: "ae-dataset-one-name",
4850
+ },
4851
+ {
4852
+ binding: "CONFLICTING_AE_DATASET_NAME",
4853
+ dataset: "ae-dataset-two-name",
4854
+ },
4855
+ ],
4823
4856
  unsafe: {
4824
4857
  bindings: [
4825
4858
  {
@@ -4859,6 +4892,7 @@ addEventListener('fetch', event => {});`
4859
4892
  - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
4860
4893
  - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
4861
4894
  - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
4895
+ - CONFLICTING_AE_DATASET_NAME assigned to multiple Analytics Engine Dataset bindings.
4862
4896
  - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
4863
4897
  - Bindings must have unique names, so that they can all be referenced in the worker.
4864
4898
  Please change your bindings to have unique names.]
@@ -4873,6 +4907,7 @@ addEventListener('fetch', event => {});`
4873
4907
  - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
4874
4908
  - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
4875
4909
  - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
4910
+ - CONFLICTING_AE_DATASET_NAME assigned to multiple Analytics Engine Dataset bindings.
4876
4911
  - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
4877
4912
  - Bindings must have unique names, so that they can all be referenced in the worker.
4878
4913
  Please change your bindings to have unique names.
@@ -4934,6 +4969,24 @@ addEventListener('fetch', event => {});`
4934
4969
  bucket_name: "r2-bucket-four-name",
4935
4970
  },
4936
4971
  ],
4972
+ analytics_engine_datasets: [
4973
+ {
4974
+ binding: "CONFLICTING_AE_DATASET_NAME",
4975
+ dataset: "ae-dataset-one-name",
4976
+ },
4977
+ {
4978
+ binding: "CONFLICTING_AE_DATASET_NAME",
4979
+ dataset: "ae-dataset-two-name",
4980
+ },
4981
+ {
4982
+ binding: "CONFLICTING_NAME_THREE",
4983
+ dataset: "ae-dataset-three-name",
4984
+ },
4985
+ {
4986
+ binding: "CONFLICTING_NAME_FOUR",
4987
+ dataset: "ae-dataset-four-name",
4988
+ },
4989
+ ],
4937
4990
  text_blobs: {
4938
4991
  CONFLICTING_NAME_THREE: "./my-entire-app-depends-on-this.cfg",
4939
4992
  CONFLICTING_NAME_FOUR: "./the-entirety-of-human-knowledge.txt",
@@ -4991,8 +5044,9 @@ addEventListener('fetch', event => {});`
4991
5044
  - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
4992
5045
  - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
4993
5046
  - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
4994
- - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
4995
- - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
5047
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Analytics Engine Dataset, Text Blob, Unsafe, Environment Variable, WASM Module, and Data Blob bindings.
5048
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Analytics Engine Dataset, Text Blob, and Unsafe bindings.
5049
+ - CONFLICTING_AE_DATASET_NAME assigned to multiple Analytics Engine Dataset bindings.
4996
5050
  - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
4997
5051
  - Bindings must have unique names, so that they can all be referenced in the worker.
4998
5052
  Please change your bindings to have unique names.]
@@ -5007,9 +5061,11 @@ addEventListener('fetch', event => {});`
5007
5061
  - CONFLICTING_DURABLE_OBJECT_NAME assigned to multiple Durable Object bindings.
5008
5062
  - CONFLICTING_KV_NAMESPACE_NAME assigned to multiple KV Namespace bindings.
5009
5063
  - CONFLICTING_R2_BUCKET_NAME assigned to multiple R2 Bucket bindings.
5010
- - CONFLICTING_NAME_THREE assigned to R2 Bucket, Text Blob, Unsafe, Environment Variable, WASM
5011
- Module, and Data Blob bindings.
5012
- - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Text Blob, and Unsafe bindings.
5064
+ - CONFLICTING_NAME_THREE assigned to R2 Bucket, Analytics Engine Dataset, Text Blob, Unsafe,
5065
+ Environment Variable, WASM Module, and Data Blob bindings.
5066
+ - CONFLICTING_NAME_FOUR assigned to R2 Bucket, Analytics Engine Dataset, Text Blob, and Unsafe
5067
+ bindings.
5068
+ - CONFLICTING_AE_DATASET_NAME assigned to multiple Analytics Engine Dataset bindings.
5013
5069
  - CONFLICTING_UNSAFE_NAME assigned to multiple Unsafe bindings.
5014
5070
  - Bindings must have unique names, so that they can all be referenced in the worker.
5015
5071
  Please change your bindings to have unique names.
@@ -5744,6 +5800,37 @@ addEventListener('fetch', event => {});`
5744
5800
  });
5745
5801
  });
5746
5802
 
5803
+ describe("[analytics_engine_datasets]", () => {
5804
+ it("should support analytics engine bindings", async () => {
5805
+ writeWranglerToml({
5806
+ analytics_engine_datasets: [
5807
+ { binding: "FOO", dataset: "foo-dataset" },
5808
+ ],
5809
+ });
5810
+ writeWorkerSource();
5811
+ mockSubDomainRequest();
5812
+ mockUploadWorkerRequest({
5813
+ expectedBindings: [
5814
+ { dataset: "foo-dataset", name: "FOO", type: "analytics_engine" },
5815
+ ],
5816
+ });
5817
+
5818
+ await runWrangler("publish index.js");
5819
+ expect(std.out).toMatchInlineSnapshot(`
5820
+ "Total Upload: xx KiB / gzip: xx KiB
5821
+ Your worker has access to the following bindings:
5822
+ - Analytics Engine Datasets:
5823
+ - FOO: foo-dataset
5824
+ Uploaded test-name (TIMINGS)
5825
+ Published test-name (TIMINGS)
5826
+ https://test-name.test-sub-domain.workers.dev
5827
+ Current Deployment ID: undefined"
5828
+ `);
5829
+ expect(std.err).toMatchInlineSnapshot(`""`);
5830
+ expect(std.warn).toMatchInlineSnapshot(`""`);
5831
+ });
5832
+ });
5833
+
5747
5834
  describe("[dispatch_namespaces]", () => {
5748
5835
  it("should support bindings to a dispatch namespace", async () => {
5749
5836
  writeWranglerToml({