wrangler 2.0.23 → 2.0.26
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.
- package/README.md +20 -2
- package/bin/wrangler.js +1 -1
- package/miniflare-dist/index.mjs +235 -47
- package/package.json +11 -6
- package/src/__tests__/configuration.test.ts +89 -17
- package/src/__tests__/dev.test.tsx +29 -4
- package/src/__tests__/generate.test.ts +93 -0
- package/src/__tests__/helpers/mock-cfetch.ts +87 -2
- package/src/__tests__/index.test.ts +10 -27
- package/src/__tests__/init.test.ts +537 -359
- package/src/__tests__/jest.setup.ts +34 -1
- package/src/__tests__/kv.test.ts +2 -2
- package/src/__tests__/metrics.test.ts +5 -0
- package/src/__tests__/pages.test.ts +14 -0
- package/src/__tests__/publish.test.ts +497 -254
- package/src/__tests__/r2.test.ts +173 -71
- package/src/__tests__/tail.test.ts +112 -42
- package/src/__tests__/user.test.ts +1 -0
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/whoami.test.tsx +60 -1
- package/src/api/dev.ts +7 -0
- package/src/bundle.ts +279 -44
- package/src/cfetch/internal.ts +73 -2
- package/src/config/config.ts +8 -3
- package/src/config/environment.ts +40 -8
- package/src/config/index.ts +13 -0
- package/src/config/validation.ts +102 -8
- package/src/create-worker-upload-form.ts +25 -0
- package/src/dev/dev.tsx +121 -28
- package/src/dev/local.tsx +88 -14
- package/src/dev/remote.tsx +39 -8
- package/src/dev/use-esbuild.ts +28 -0
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +160 -0
- package/src/dev.tsx +107 -80
- package/src/generate.ts +112 -14
- package/src/index.tsx +212 -4
- package/src/init.ts +111 -38
- package/src/inspect.ts +90 -5
- package/src/metrics/index.ts +1 -0
- package/src/metrics/metrics-dispatcher.ts +1 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +2 -2
- package/src/miniflare-cli/assets.ts +27 -16
- package/src/miniflare-cli/index.ts +124 -2
- package/src/module-collection.ts +3 -3
- package/src/pages/build.tsx +75 -41
- package/src/pages/constants.ts +5 -0
- package/src/pages/deployments.tsx +10 -10
- package/src/pages/dev.tsx +177 -52
- package/src/pages/errors.ts +22 -0
- package/src/pages/functions/buildPlugin.ts +4 -0
- package/src/pages/functions/buildWorker.ts +4 -0
- package/src/pages/functions/routes-consolidation.test.ts +250 -0
- package/src/pages/functions/routes-consolidation.ts +73 -0
- package/src/pages/functions/routes-transformation.test.ts +271 -0
- package/src/pages/functions/routes-transformation.ts +122 -0
- package/src/pages/functions.tsx +96 -0
- package/src/pages/index.tsx +65 -55
- package/src/pages/projects.tsx +9 -3
- package/src/pages/publish.tsx +76 -23
- package/src/pages/types.ts +9 -0
- package/src/pages/upload.tsx +38 -21
- package/src/publish.ts +126 -112
- package/src/r2.ts +81 -0
- package/src/tail/filters.ts +3 -1
- package/src/tail/index.ts +15 -2
- package/src/tail/printing.ts +43 -3
- package/src/user/user.tsx +20 -2
- package/src/whoami.tsx +79 -1
- package/src/worker.ts +12 -0
- package/templates/first-party-worker-module-facade.ts +18 -0
- package/templates/format-dev-errors.ts +32 -0
- package/templates/pages-template-plugin.ts +16 -4
- package/templates/pages-template-worker.ts +16 -5
- package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
- package/templates/service-bindings-module-facade.js +54 -0
- package/templates/service-bindings-sw-facade.js +42 -0
- package/wrangler-dist/cli.d.ts +7 -0
- package/wrangler-dist/cli.js +40851 -15332
package/src/__tests__/r2.test.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
1
2
|
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
setMockFetchR2Objects,
|
|
5
|
+
setMockResponse,
|
|
6
|
+
unsetAllMocks,
|
|
7
|
+
} from "./helpers/mock-cfetch";
|
|
3
8
|
import { mockConsoleMethods } from "./helpers/mock-console";
|
|
4
9
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
5
10
|
import { runWrangler } from "./helpers/run-wrangler";
|
|
@@ -22,26 +27,26 @@ describe("wrangler", () => {
|
|
|
22
27
|
runWrangler("r2 bucket foo")
|
|
23
28
|
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown argument: foo"`);
|
|
24
29
|
expect(std.err).toMatchInlineSnapshot(`
|
|
25
|
-
|
|
30
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mUnknown argument: foo[0m
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
"
|
|
33
|
+
`);
|
|
29
34
|
expect(std.out).toMatchInlineSnapshot(`
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
"
|
|
36
|
+
wrangler r2 bucket
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
Manage R2 buckets
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
Commands:
|
|
41
|
+
wrangler r2 bucket create <name> Create a new R2 bucket
|
|
42
|
+
wrangler r2 bucket list List R2 buckets
|
|
43
|
+
wrangler r2 bucket delete <name> Delete an R2 bucket
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
Flags:
|
|
46
|
+
-c, --config Path to .toml configuration file [string]
|
|
47
|
+
-h, --help Show help [boolean]
|
|
48
|
+
-v, --version Show version number [boolean]"
|
|
49
|
+
`);
|
|
45
50
|
});
|
|
46
51
|
|
|
47
52
|
describe("list", () => {
|
|
@@ -95,24 +100,24 @@ describe("wrangler", () => {
|
|
|
95
100
|
`"Not enough non-option arguments: got 0, need at least 1"`
|
|
96
101
|
);
|
|
97
102
|
expect(std.out).toMatchInlineSnapshot(`
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
"
|
|
104
|
+
wrangler r2 bucket create <name>
|
|
100
105
|
|
|
101
|
-
|
|
106
|
+
Create a new R2 bucket
|
|
102
107
|
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
Positionals:
|
|
109
|
+
name The name of the new bucket [string] [required]
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
Flags:
|
|
112
|
+
-c, --config Path to .toml configuration file [string]
|
|
113
|
+
-h, --help Show help [boolean]
|
|
114
|
+
-v, --version Show version number [boolean]"
|
|
115
|
+
`);
|
|
111
116
|
expect(std.err).toMatchInlineSnapshot(`
|
|
112
|
-
|
|
117
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mNot enough non-option arguments: got 0, need at least 1[0m
|
|
113
118
|
|
|
114
|
-
|
|
115
|
-
|
|
119
|
+
"
|
|
120
|
+
`);
|
|
116
121
|
});
|
|
117
122
|
|
|
118
123
|
it("should error if the bucket to create contains spaces", async () => {
|
|
@@ -122,33 +127,33 @@ describe("wrangler", () => {
|
|
|
122
127
|
`"Unknown arguments: def, ghi"`
|
|
123
128
|
);
|
|
124
129
|
expect(std.out).toMatchInlineSnapshot(`
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
"
|
|
131
|
+
wrangler r2 bucket create <name>
|
|
127
132
|
|
|
128
|
-
|
|
133
|
+
Create a new R2 bucket
|
|
129
134
|
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
Positionals:
|
|
136
|
+
name The name of the new bucket [string] [required]
|
|
132
137
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
Flags:
|
|
139
|
+
-c, --config Path to .toml configuration file [string]
|
|
140
|
+
-h, --help Show help [boolean]
|
|
141
|
+
-v, --version Show version number [boolean]"
|
|
142
|
+
`);
|
|
138
143
|
expect(std.err).toMatchInlineSnapshot(`
|
|
139
|
-
|
|
144
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mUnknown arguments: def, ghi[0m
|
|
140
145
|
|
|
141
|
-
|
|
142
|
-
|
|
146
|
+
"
|
|
147
|
+
`);
|
|
143
148
|
});
|
|
144
149
|
|
|
145
150
|
it("should create a bucket", async () => {
|
|
146
151
|
const requests = mockCreateRequest("testBucket");
|
|
147
152
|
await runWrangler("r2 bucket create testBucket");
|
|
148
153
|
expect(std.out).toMatchInlineSnapshot(`
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
154
|
+
"Creating bucket testBucket.
|
|
155
|
+
Created bucket testBucket."
|
|
156
|
+
`);
|
|
152
157
|
expect(requests.count).toEqual(1);
|
|
153
158
|
});
|
|
154
159
|
});
|
|
@@ -175,24 +180,24 @@ describe("wrangler", () => {
|
|
|
175
180
|
`"Not enough non-option arguments: got 0, need at least 1"`
|
|
176
181
|
);
|
|
177
182
|
expect(std.out).toMatchInlineSnapshot(`
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
"
|
|
184
|
+
wrangler r2 bucket delete <name>
|
|
180
185
|
|
|
181
|
-
|
|
186
|
+
Delete an R2 bucket
|
|
182
187
|
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
Positionals:
|
|
189
|
+
name The name of the bucket to delete [string] [required]
|
|
185
190
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
+
Flags:
|
|
192
|
+
-c, --config Path to .toml configuration file [string]
|
|
193
|
+
-h, --help Show help [boolean]
|
|
194
|
+
-v, --version Show version number [boolean]"
|
|
195
|
+
`);
|
|
191
196
|
expect(std.err).toMatchInlineSnapshot(`
|
|
192
|
-
|
|
197
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mNot enough non-option arguments: got 0, need at least 1[0m
|
|
193
198
|
|
|
194
|
-
|
|
195
|
-
|
|
199
|
+
"
|
|
200
|
+
`);
|
|
196
201
|
});
|
|
197
202
|
|
|
198
203
|
it("should error if the bucket name to delete contains spaces", async () => {
|
|
@@ -202,24 +207,24 @@ describe("wrangler", () => {
|
|
|
202
207
|
`"Unknown arguments: def, ghi"`
|
|
203
208
|
);
|
|
204
209
|
expect(std.out).toMatchInlineSnapshot(`
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
"
|
|
211
|
+
wrangler r2 bucket delete <name>
|
|
207
212
|
|
|
208
|
-
|
|
213
|
+
Delete an R2 bucket
|
|
209
214
|
|
|
210
|
-
|
|
211
|
-
|
|
215
|
+
Positionals:
|
|
216
|
+
name The name of the bucket to delete [string] [required]
|
|
212
217
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
Flags:
|
|
219
|
+
-c, --config Path to .toml configuration file [string]
|
|
220
|
+
-h, --help Show help [boolean]
|
|
221
|
+
-v, --version Show version number [boolean]"
|
|
222
|
+
`);
|
|
218
223
|
expect(std.err).toMatchInlineSnapshot(`
|
|
219
|
-
|
|
224
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mUnknown arguments: def, ghi[0m
|
|
220
225
|
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
"
|
|
227
|
+
`);
|
|
223
228
|
});
|
|
224
229
|
|
|
225
230
|
it("should delete a bucket specified by name", async () => {
|
|
@@ -229,5 +234,102 @@ describe("wrangler", () => {
|
|
|
229
234
|
});
|
|
230
235
|
});
|
|
231
236
|
});
|
|
237
|
+
|
|
238
|
+
describe("r2 object", () => {
|
|
239
|
+
it("should download R2 object from bucket", async () => {
|
|
240
|
+
setMockFetchR2Objects({
|
|
241
|
+
accountId: "some-account-id",
|
|
242
|
+
bucketName: "bucketName-object-test",
|
|
243
|
+
objectName: "wormhole-img.png",
|
|
244
|
+
mockResponse: "R2-objects-test-data",
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
await runWrangler(
|
|
248
|
+
`r2 object get bucketName-object-test/wormhole-img.png --file ./wormhole-img.png`
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
252
|
+
"Downloading \\"wormhole-img.png\\" from \\"bucketName-object-test\\".
|
|
253
|
+
Download complete."
|
|
254
|
+
`);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("should upload R2 object from bucket", async () => {
|
|
258
|
+
setMockFetchR2Objects({
|
|
259
|
+
accountId: "some-account-id",
|
|
260
|
+
bucketName: "bucketName-object-test",
|
|
261
|
+
objectName: "wormhole-img.png",
|
|
262
|
+
});
|
|
263
|
+
fs.writeFileSync("wormhole-img.png", "passageway");
|
|
264
|
+
await runWrangler(
|
|
265
|
+
`r2 object put bucketName-object-test/wormhole-img.png --file ./wormhole-img.png`
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
269
|
+
"Creating object \\"wormhole-img.png\\" in bucket \\"bucketName-object-test\\".
|
|
270
|
+
Upload complete."
|
|
271
|
+
`);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("should pass all fetch option flags into requestInit", async () => {
|
|
275
|
+
fs.writeFileSync("wormhole-img.png", "passageway");
|
|
276
|
+
setMockFetchR2Objects({
|
|
277
|
+
accountId: "some-account-id",
|
|
278
|
+
bucketName: "bucketName-object-test",
|
|
279
|
+
objectName: "wormhole-img.png",
|
|
280
|
+
});
|
|
281
|
+
const flags =
|
|
282
|
+
"--ct content-type --cd content-disposition --ce content-encoding --cl content-lang --cc cache-control --e expire-time";
|
|
283
|
+
|
|
284
|
+
await runWrangler(
|
|
285
|
+
`r2 object put bucketName-object-test/wormhole-img.png ${flags} --file wormhole-img.png`
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
289
|
+
"Creating object \\"wormhole-img.png\\" in bucket \\"bucketName-object-test\\".
|
|
290
|
+
Upload complete."
|
|
291
|
+
`);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it("should delete R2 object from bucket", async () => {
|
|
295
|
+
setMockFetchR2Objects({
|
|
296
|
+
accountId: "some-account-id",
|
|
297
|
+
bucketName: "bucketName-object-test",
|
|
298
|
+
objectName: "wormhole-img.png",
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
await runWrangler(
|
|
302
|
+
`r2 object delete bucketName-object-test/wormhole-img.png`
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
expect(std.out).toMatchInlineSnapshot(`
|
|
306
|
+
"Deleting object \\"wormhole-img.png\\" from bucket \\"bucketName-object-test\\".
|
|
307
|
+
Delete complete."
|
|
308
|
+
`);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it("should not allow `--pipe` & `--file` to run together", async () => {
|
|
312
|
+
fs.writeFileSync("wormhole-img.png", "passageway");
|
|
313
|
+
setMockFetchR2Objects({
|
|
314
|
+
accountId: "some-account-id",
|
|
315
|
+
bucketName: "bucketName-object-test",
|
|
316
|
+
objectName: "wormhole-img.png",
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
await expect(
|
|
320
|
+
runWrangler(
|
|
321
|
+
`r2 object put bucketName-object-test/wormhole-img.png --pipe --file wormhole-img.png`
|
|
322
|
+
)
|
|
323
|
+
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
324
|
+
`"Arguments pipe and file are mutually exclusive"`
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
expect(std.err).toMatchInlineSnapshot(`
|
|
328
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mArguments pipe and file are mutually exclusive[0m
|
|
329
|
+
|
|
330
|
+
"
|
|
331
|
+
`);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
232
334
|
});
|
|
233
335
|
});
|
|
@@ -6,7 +6,12 @@ import { mockConsoleMethods } from "./helpers/mock-console";
|
|
|
6
6
|
import { useMockIsTTY } from "./helpers/mock-istty";
|
|
7
7
|
import { runInTempDir } from "./helpers/run-in-tmp";
|
|
8
8
|
import { runWrangler } from "./helpers/run-wrangler";
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
TailEventMessage,
|
|
11
|
+
RequestEvent,
|
|
12
|
+
ScheduledEvent,
|
|
13
|
+
AlarmEvent,
|
|
14
|
+
} from "../tail";
|
|
10
15
|
import type WebSocket from "ws";
|
|
11
16
|
|
|
12
17
|
describe("tail", () => {
|
|
@@ -113,7 +118,7 @@ describe("tail", () => {
|
|
|
113
118
|
const api = mockWebsocketAPIs();
|
|
114
119
|
await runWrangler("tail test-worker --status error");
|
|
115
120
|
await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
|
|
116
|
-
{ outcome: ["exception", "exceededCpu", "unknown"] },
|
|
121
|
+
{ outcome: ["exception", "exceededCpu", "exceededMemory", "unknown"] },
|
|
117
122
|
]);
|
|
118
123
|
});
|
|
119
124
|
|
|
@@ -121,7 +126,15 @@ describe("tail", () => {
|
|
|
121
126
|
const api = mockWebsocketAPIs();
|
|
122
127
|
await runWrangler("tail test-worker --status error --status canceled");
|
|
123
128
|
await expect(api.nextMessageJson()).resolves.toHaveProperty("filters", [
|
|
124
|
-
{
|
|
129
|
+
{
|
|
130
|
+
outcome: [
|
|
131
|
+
"exception",
|
|
132
|
+
"exceededCpu",
|
|
133
|
+
"exceededMemory",
|
|
134
|
+
"unknown",
|
|
135
|
+
"canceled",
|
|
136
|
+
],
|
|
137
|
+
},
|
|
125
138
|
]);
|
|
126
139
|
});
|
|
127
140
|
|
|
@@ -208,7 +221,15 @@ describe("tail", () => {
|
|
|
208
221
|
const expectedWebsocketMessage = {
|
|
209
222
|
filters: [
|
|
210
223
|
{ sampling_rate },
|
|
211
|
-
{
|
|
224
|
+
{
|
|
225
|
+
outcome: [
|
|
226
|
+
"ok",
|
|
227
|
+
"exception",
|
|
228
|
+
"exceededCpu",
|
|
229
|
+
"exceededMemory",
|
|
230
|
+
"unknown",
|
|
231
|
+
],
|
|
232
|
+
},
|
|
212
233
|
{ method },
|
|
213
234
|
{ header: { key: "X-HELLO", query: "world" } },
|
|
214
235
|
{ client_ip },
|
|
@@ -251,6 +272,18 @@ describe("tail", () => {
|
|
|
251
272
|
expect(std.out).toMatch(deserializeToJson(serializedMessage));
|
|
252
273
|
});
|
|
253
274
|
|
|
275
|
+
it("logs alarm messages in json format", async () => {
|
|
276
|
+
const api = mockWebsocketAPIs();
|
|
277
|
+
await runWrangler("tail test-worker --format json");
|
|
278
|
+
|
|
279
|
+
const event = generateMockAlarmEvent();
|
|
280
|
+
const message = generateMockEventMessage({ event });
|
|
281
|
+
const serializedMessage = serialize(message);
|
|
282
|
+
|
|
283
|
+
api.ws.send(serializedMessage);
|
|
284
|
+
expect(std.out).toMatch(deserializeToJson(serializedMessage));
|
|
285
|
+
});
|
|
286
|
+
|
|
254
287
|
it("logs request messages in pretty format", async () => {
|
|
255
288
|
const api = mockWebsocketAPIs();
|
|
256
289
|
await runWrangler("tail test-worker --format pretty");
|
|
@@ -271,10 +304,10 @@ describe("tail", () => {
|
|
|
271
304
|
"[mock expiration date]"
|
|
272
305
|
)
|
|
273
306
|
).toMatchInlineSnapshot(`
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
307
|
+
"Successfully created tail, expires at [mock expiration date]
|
|
308
|
+
Connected to test-worker, waiting for logs...
|
|
309
|
+
GET https://example.org/ - Ok @ [mock event timestamp]"
|
|
310
|
+
`);
|
|
278
311
|
});
|
|
279
312
|
|
|
280
313
|
it("logs scheduled messages in pretty format", async () => {
|
|
@@ -297,35 +330,61 @@ describe("tail", () => {
|
|
|
297
330
|
"[mock expiration date]"
|
|
298
331
|
)
|
|
299
332
|
).toMatchInlineSnapshot(`
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
333
|
+
"Successfully created tail, expires at [mock expiration date]
|
|
334
|
+
Connected to test-worker, waiting for logs...
|
|
335
|
+
\\"* * * * *\\" @ [mock timestamp string] - Ok"
|
|
336
|
+
`);
|
|
304
337
|
});
|
|
305
338
|
|
|
306
|
-
it("
|
|
339
|
+
it("logs alarm messages in pretty format", async () => {
|
|
307
340
|
const api = mockWebsocketAPIs();
|
|
308
341
|
await runWrangler("tail test-worker --format pretty");
|
|
309
342
|
|
|
310
|
-
const
|
|
343
|
+
const event = generateMockAlarmEvent();
|
|
344
|
+
const message = generateMockEventMessage({ event });
|
|
311
345
|
const serializedMessage = serialize(message);
|
|
312
346
|
|
|
313
347
|
api.ws.send(serializedMessage);
|
|
314
348
|
expect(
|
|
315
349
|
std.out
|
|
316
350
|
.replace(
|
|
317
|
-
new Date(
|
|
318
|
-
"[mock
|
|
351
|
+
new Date(mockEventScheduledTime).toLocaleString(),
|
|
352
|
+
"[mock scheduled time]"
|
|
319
353
|
)
|
|
320
354
|
.replace(
|
|
321
355
|
mockTailExpiration.toLocaleString(),
|
|
322
356
|
"[mock expiration date]"
|
|
323
357
|
)
|
|
324
358
|
).toMatchInlineSnapshot(`
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
359
|
+
"Successfully created tail, expires at [mock expiration date]
|
|
360
|
+
Connected to test-worker, waiting for logs...
|
|
361
|
+
Alarm @ [mock scheduled time] - Ok"
|
|
362
|
+
`);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("should not crash when the tail message has a void event", async () => {
|
|
366
|
+
const api = mockWebsocketAPIs();
|
|
367
|
+
await runWrangler("tail test-worker --format pretty");
|
|
368
|
+
|
|
369
|
+
const message = generateMockEventMessage({ event: null });
|
|
370
|
+
const serializedMessage = serialize(message);
|
|
371
|
+
|
|
372
|
+
api.ws.send(serializedMessage);
|
|
373
|
+
expect(
|
|
374
|
+
std.out
|
|
375
|
+
.replace(
|
|
376
|
+
mockTailExpiration.toLocaleString(),
|
|
377
|
+
"[mock expiration date]"
|
|
378
|
+
)
|
|
379
|
+
.replace(
|
|
380
|
+
new Date(mockEventTimestamp).toLocaleString(),
|
|
381
|
+
"[mock timestamp string]"
|
|
382
|
+
)
|
|
383
|
+
).toMatchInlineSnapshot(`
|
|
384
|
+
"Successfully created tail, expires at [mock expiration date]
|
|
385
|
+
Connected to test-worker, waiting for logs...
|
|
386
|
+
Unknown Event - Ok @ [mock timestamp string]"
|
|
387
|
+
`);
|
|
329
388
|
});
|
|
330
389
|
|
|
331
390
|
it("defaults to logging in pretty format when the output is a TTY", async () => {
|
|
@@ -349,10 +408,10 @@ describe("tail", () => {
|
|
|
349
408
|
"[mock expiration date]"
|
|
350
409
|
)
|
|
351
410
|
).toMatchInlineSnapshot(`
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
411
|
+
"Successfully created tail, expires at [mock expiration date]
|
|
412
|
+
Connected to test-worker, waiting for logs...
|
|
413
|
+
GET https://example.org/ - Ok @ [mock event timestamp]"
|
|
414
|
+
`);
|
|
356
415
|
});
|
|
357
416
|
|
|
358
417
|
it("defaults to logging in json format when the output is not a TTY", async () => {
|
|
@@ -405,21 +464,21 @@ describe("tail", () => {
|
|
|
405
464
|
"[mock expiration date]"
|
|
406
465
|
)
|
|
407
466
|
).toMatchInlineSnapshot(`
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
467
|
+
"Successfully created tail, expires at [mock expiration date]
|
|
468
|
+
Connected to test-worker, waiting for logs...
|
|
469
|
+
GET https://example.org/ - Ok @ [mock event timestamp]
|
|
470
|
+
(log) some string
|
|
471
|
+
(log) { complex: 'object' }
|
|
472
|
+
(error) 1234"
|
|
473
|
+
`);
|
|
415
474
|
expect(std.err).toMatchInlineSnapshot(`
|
|
416
|
-
|
|
475
|
+
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1m Error: some error[0m
|
|
417
476
|
|
|
418
477
|
|
|
419
|
-
|
|
478
|
+
[31mX [41;31m[[41;97mERROR[41;31m][0m [1m Error: { complex: 'error' }[0m
|
|
420
479
|
|
|
421
|
-
|
|
422
|
-
|
|
480
|
+
"
|
|
481
|
+
`);
|
|
423
482
|
expect(std.warn).toMatchInlineSnapshot(`""`);
|
|
424
483
|
});
|
|
425
484
|
});
|
|
@@ -437,8 +496,8 @@ describe("tail", () => {
|
|
|
437
496
|
* @returns the same type we expect when deserializing in wrangler
|
|
438
497
|
*/
|
|
439
498
|
function serialize(message: TailEventMessage): WebSocket.RawData {
|
|
440
|
-
if (
|
|
441
|
-
// `ScheduledEvent`s work just fine
|
|
499
|
+
if (!isRequest(message.event)) {
|
|
500
|
+
// `ScheduledEvent`s and `TailEvent`s work just fine
|
|
442
501
|
const stringified = JSON.stringify(message);
|
|
443
502
|
return Buffer.from(stringified, "utf-8");
|
|
444
503
|
} else {
|
|
@@ -470,12 +529,12 @@ function serialize(message: TailEventMessage): WebSocket.RawData {
|
|
|
470
529
|
* Small helper to disambiguate the event types possible in a `TailEventMessage`
|
|
471
530
|
*
|
|
472
531
|
* @param event A TailEvent
|
|
473
|
-
* @returns
|
|
532
|
+
* @returns true if `event` is a RequestEvent
|
|
474
533
|
*/
|
|
475
|
-
function
|
|
476
|
-
event: ScheduledEvent | RequestEvent | undefined | null
|
|
477
|
-
): event is
|
|
478
|
-
return Boolean(event && "
|
|
534
|
+
function isRequest(
|
|
535
|
+
event: ScheduledEvent | RequestEvent | AlarmEvent | undefined | null
|
|
536
|
+
): event is RequestEvent {
|
|
537
|
+
return Boolean(event && "request" in event);
|
|
479
538
|
}
|
|
480
539
|
|
|
481
540
|
/**
|
|
@@ -559,6 +618,11 @@ const mockTailExpiration = new Date(3005, 1);
|
|
|
559
618
|
*/
|
|
560
619
|
const mockEventTimestamp = 1645454470467;
|
|
561
620
|
|
|
621
|
+
/**
|
|
622
|
+
* Default value for event time ISO strings
|
|
623
|
+
*/
|
|
624
|
+
const mockEventScheduledTime = new Date(mockEventTimestamp).toISOString();
|
|
625
|
+
|
|
562
626
|
/**
|
|
563
627
|
* Mock out the API hit during Tail deletion
|
|
564
628
|
*
|
|
@@ -696,3 +760,9 @@ function generateMockScheduledEvent(
|
|
|
696
760
|
scheduledTime: opts?.scheduledTime || mockEventTimestamp,
|
|
697
761
|
};
|
|
698
762
|
}
|
|
763
|
+
|
|
764
|
+
function generateMockAlarmEvent(opts?: Partial<AlarmEvent>): AlarmEvent {
|
|
765
|
+
return {
|
|
766
|
+
scheduledTime: opts?.scheduledTime || mockEventScheduledTime,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { validateDevProps } from "../dev/validate-dev-props";
|
|
2
|
+
import type { DevProps } from "../dev/dev";
|
|
3
|
+
|
|
4
|
+
describe("validateDevProps", () => {
|
|
5
|
+
it("should throw if the user tries to use the service-worker format with an `assets` directory", () => {
|
|
6
|
+
const props = {
|
|
7
|
+
isWorkersSite: false,
|
|
8
|
+
assetPaths: ["assets"],
|
|
9
|
+
entry: { format: "service-worker" },
|
|
10
|
+
bindings: {},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
expect(() => validateDevProps(props as unknown as DevProps)).toThrowError(
|
|
14
|
+
"You cannot use the service-worker format with an `assets` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should throw if the user tries to configure [wasm_modules] with an ES module worker", () => {
|
|
19
|
+
const props = {
|
|
20
|
+
isWorkersSite: false,
|
|
21
|
+
assetPaths: [],
|
|
22
|
+
entry: { format: "modules" },
|
|
23
|
+
bindings: { wasm_modules: true },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
expect(() => validateDevProps(props as unknown as DevProps)).toThrowError(
|
|
27
|
+
"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should throw if the user tries to configure [text_blobs] with an ES module worker", () => {
|
|
32
|
+
const props = {
|
|
33
|
+
isWorkersSite: false,
|
|
34
|
+
assetPaths: [],
|
|
35
|
+
entry: { format: "modules" },
|
|
36
|
+
bindings: { text_blobs: true },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
expect(() => validateDevProps(props as unknown as DevProps)).toThrowError(
|
|
40
|
+
"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should throw if the user tries to configure [data_blobs] with an ES module worker", () => {
|
|
45
|
+
const props = {
|
|
46
|
+
isWorkersSite: false,
|
|
47
|
+
assetPaths: [],
|
|
48
|
+
entry: { format: "modules" },
|
|
49
|
+
bindings: { data_blobs: true },
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
expect(() => validateDevProps(props as unknown as DevProps)).toThrowError(
|
|
53
|
+
"You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
});
|