wrangler 2.1.14 → 2.2.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.
- package/miniflare-dist/index.mjs +3 -1
- package/package.json +2 -1
- package/src/__tests__/access.test.ts +25 -0
- package/src/__tests__/api-dev.test.ts +1 -1
- package/src/__tests__/api-devregistry.test.js +2 -2
- package/src/__tests__/configuration.test.ts +119 -2
- package/src/__tests__/d1.test.ts +2 -0
- package/src/__tests__/deployments.test.ts +22 -22
- package/src/__tests__/dev.test.tsx +167 -15
- package/src/__tests__/helpers/msw/handlers/access.ts +13 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +22 -43
- package/src/__tests__/helpers/msw/handlers/zones.ts +22 -0
- package/src/__tests__/helpers/msw/index.ts +4 -0
- package/src/__tests__/index.test.ts +42 -33
- package/src/__tests__/init.test.ts +88 -4
- package/src/__tests__/jest.setup.ts +11 -0
- package/src/__tests__/kv.test.ts +400 -400
- package/src/__tests__/pages.test.ts +140 -28
- package/src/__tests__/publish.test.ts +1161 -647
- package/src/__tests__/pubsub.test.ts +3 -0
- package/src/__tests__/queues.test.ts +371 -0
- package/src/__tests__/r2.test.ts +57 -52
- package/src/__tests__/worker-namespace.test.ts +15 -10
- package/src/bundle-reporter.tsx +41 -2
- package/src/bundle.ts +59 -30
- package/src/cli.ts +0 -1
- package/src/config/environment.ts +50 -0
- package/src/config/index.ts +41 -0
- package/src/config/validation.ts +173 -0
- package/src/create-worker-preview.ts +10 -3
- package/src/create-worker-upload-form.ts +12 -0
- package/src/d1/backups.tsx +11 -5
- package/src/d1/execute.tsx +52 -47
- package/src/d1/index.ts +2 -1
- package/src/delete.ts +7 -10
- package/src/deployments.ts +73 -0
- package/src/deprecated/index.ts +9 -24
- package/src/dev/dev-vars.ts +11 -8
- package/src/dev/dev.tsx +12 -0
- package/src/dev/local.tsx +26 -0
- package/src/dev/remote.tsx +2 -0
- package/src/dev/start-server.ts +7 -0
- package/src/dev/use-esbuild.ts +12 -5
- package/src/dev.tsx +12 -9
- package/src/dispatch-namespace.ts +4 -3
- package/src/index.tsx +61 -45
- package/src/init.ts +4 -4
- package/src/inspect.ts +21 -1
- package/src/is-interactive.ts +4 -0
- package/src/kv/index.ts +5 -54
- package/src/logger.ts +12 -0
- package/src/pages/constants.ts +2 -0
- package/src/pages/upload.tsx +42 -15
- package/src/proxy.ts +38 -6
- package/src/publish/index.ts +11 -8
- package/src/publish/publish.ts +151 -30
- package/src/pubsub/pubsub-commands.tsx +3 -2
- package/src/queues/cli/commands/consumer/add.ts +71 -0
- package/src/queues/cli/commands/consumer/index.ts +22 -0
- package/src/queues/cli/commands/consumer/remove.ts +38 -0
- package/src/queues/cli/commands/create.ts +25 -0
- package/src/queues/cli/commands/delete.ts +26 -0
- package/src/queues/cli/commands/index.ts +33 -0
- package/src/queues/cli/commands/list.ts +25 -0
- package/src/queues/client.ts +135 -0
- package/src/secret/index.ts +14 -39
- package/src/tail/index.ts +5 -8
- package/src/user/access.ts +69 -0
- package/src/worker.ts +7 -0
- package/src/yargs-types.ts +15 -2
- package/src/zones.ts +31 -5
- package/templates/pages-template-plugin.ts +4 -0
- package/templates/pages-template-worker.ts +21 -4
- package/wrangler-dist/cli.d.ts +42 -0
- package/wrangler-dist/cli.js +4559 -3228
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type BuilderCallback } from "yargs";
|
|
2
|
+
import { type CommonYargsOptions } from "../../../yargs-types";
|
|
3
|
+
import { consumers } from "./consumer";
|
|
4
|
+
|
|
5
|
+
import { options as createOptions, handler as createHandler } from "./create";
|
|
6
|
+
import { options as deleteOptions, handler as deleteHandler } from "./delete";
|
|
7
|
+
import { options as listOptions, handler as listHandler } from "./list";
|
|
8
|
+
|
|
9
|
+
export const queues: BuilderCallback<CommonYargsOptions, unknown> = (yargs) => {
|
|
10
|
+
yargs.command("list", "List Queues", listOptions, listHandler);
|
|
11
|
+
|
|
12
|
+
yargs.command(
|
|
13
|
+
"create <name>",
|
|
14
|
+
"Create a Queue",
|
|
15
|
+
createOptions,
|
|
16
|
+
createHandler
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
yargs.command(
|
|
20
|
+
"delete <name>",
|
|
21
|
+
"Delete a Queue",
|
|
22
|
+
deleteOptions,
|
|
23
|
+
deleteHandler
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
yargs.command(
|
|
27
|
+
"consumer",
|
|
28
|
+
"Configure Queue Consumers",
|
|
29
|
+
async (consumersYargs) => {
|
|
30
|
+
await consumers(consumersYargs);
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Argv } from "yargs";
|
|
2
|
+
import { readConfig } from "../../../config";
|
|
3
|
+
import { logger } from "../../../logger";
|
|
4
|
+
import { listQueues } from "../../client";
|
|
5
|
+
|
|
6
|
+
interface Args {
|
|
7
|
+
config?: string;
|
|
8
|
+
page?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function options(yargs: Argv): Argv<Args> {
|
|
12
|
+
return yargs.options({
|
|
13
|
+
page: {
|
|
14
|
+
type: "number",
|
|
15
|
+
describe: "Page number for pagination",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function handler(args: Args) {
|
|
21
|
+
const config = readConfig(args.config, args);
|
|
22
|
+
|
|
23
|
+
const queues = await listQueues(config, args.page);
|
|
24
|
+
logger.log(JSON.stringify(queues));
|
|
25
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { fetchResult } from "../cfetch";
|
|
2
|
+
import { type Config } from "../config";
|
|
3
|
+
import { requireAuth } from "../user";
|
|
4
|
+
|
|
5
|
+
export async function createQueue(
|
|
6
|
+
config: Config,
|
|
7
|
+
body: CreateQueueBody
|
|
8
|
+
): Promise<QueueResponse> {
|
|
9
|
+
const accountId = await requireAuth(config);
|
|
10
|
+
return await fetchResult(`/accounts/${accountId}/workers/queues`, {
|
|
11
|
+
method: "POST",
|
|
12
|
+
body: JSON.stringify(body),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CreateQueueBody {
|
|
17
|
+
queue_name: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface QueueResponse {
|
|
21
|
+
queue_name: string;
|
|
22
|
+
created_on: string;
|
|
23
|
+
modified_on: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function deleteQueue(
|
|
27
|
+
config: Config,
|
|
28
|
+
queueName: string
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
const accountId = await requireAuth(config);
|
|
31
|
+
return await fetchResult(
|
|
32
|
+
`/accounts/${accountId}/workers/queues/${queueName}`,
|
|
33
|
+
{
|
|
34
|
+
method: "DELETE",
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// TODO(soon) show detailed queue response
|
|
40
|
+
export async function listQueues(
|
|
41
|
+
config: Config,
|
|
42
|
+
page?: number
|
|
43
|
+
): Promise<QueueResponse[]> {
|
|
44
|
+
page = page ?? 1;
|
|
45
|
+
const accountId = await requireAuth(config);
|
|
46
|
+
return await fetchResult(
|
|
47
|
+
`/accounts/${accountId}/workers/queues`,
|
|
48
|
+
{},
|
|
49
|
+
new URLSearchParams({ page: page.toString() })
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function getQueue(
|
|
54
|
+
config: Config,
|
|
55
|
+
queueName: string
|
|
56
|
+
): Promise<QueueResponse> {
|
|
57
|
+
const accountId = await requireAuth(config);
|
|
58
|
+
return await fetchResult(
|
|
59
|
+
`/accounts/${accountId}/workers/queues/${queueName}`,
|
|
60
|
+
{}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function postConsumer(
|
|
65
|
+
config: Config,
|
|
66
|
+
queueName: string,
|
|
67
|
+
body: PostConsumerBody
|
|
68
|
+
): Promise<ConsumerResponse> {
|
|
69
|
+
const accountId = await requireAuth(config);
|
|
70
|
+
return fetchResult(
|
|
71
|
+
`/accounts/${accountId}/workers/queues/${queueName}/consumers`,
|
|
72
|
+
{
|
|
73
|
+
method: "POST",
|
|
74
|
+
body: JSON.stringify(body),
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface PutConsumerBody {
|
|
80
|
+
settings: ConsumerSettings;
|
|
81
|
+
dead_letter_queue?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface PostConsumerBody extends PutConsumerBody {
|
|
85
|
+
script_name: string;
|
|
86
|
+
environment_name: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface ConsumerSettings {
|
|
90
|
+
batch_size?: number;
|
|
91
|
+
max_retries?: number;
|
|
92
|
+
max_wait_time_ms?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ConsumerResponse extends PostConsumerBody {
|
|
96
|
+
queue_name: string;
|
|
97
|
+
script_name: string;
|
|
98
|
+
environment_name: string;
|
|
99
|
+
settings: ConsumerSettings;
|
|
100
|
+
dead_letter_queue?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function deleteConsumer(
|
|
104
|
+
config: Config,
|
|
105
|
+
queueName: string,
|
|
106
|
+
scriptName: string,
|
|
107
|
+
envName?: string
|
|
108
|
+
): Promise<void> {
|
|
109
|
+
const accountId = await requireAuth(config);
|
|
110
|
+
let resource = `/accounts/${accountId}/workers/queues/${queueName}/consumers/${scriptName}`;
|
|
111
|
+
if (envName !== undefined) {
|
|
112
|
+
resource += `/environments/${envName}`;
|
|
113
|
+
}
|
|
114
|
+
return fetchResult(resource, {
|
|
115
|
+
method: "DELETE",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function putConsumer(
|
|
120
|
+
config: Config,
|
|
121
|
+
queueName: string,
|
|
122
|
+
scriptName: string,
|
|
123
|
+
envName: string | undefined,
|
|
124
|
+
body: PutConsumerBody
|
|
125
|
+
): Promise<ConsumerResponse> {
|
|
126
|
+
const accountId = await requireAuth(config);
|
|
127
|
+
let resource = `/accounts/${accountId}/workers/queues/${queueName}/consumers/${scriptName}`;
|
|
128
|
+
if (envName !== undefined) {
|
|
129
|
+
resource += `/environments/${envName}`;
|
|
130
|
+
}
|
|
131
|
+
return fetchResult(resource, {
|
|
132
|
+
method: "PUT",
|
|
133
|
+
body: JSON.stringify(body),
|
|
134
|
+
});
|
|
135
|
+
}
|
package/src/secret/index.ts
CHANGED
|
@@ -14,12 +14,13 @@ import { parseJSON, readFileSync } from "../parse";
|
|
|
14
14
|
import { requireAuth } from "../user";
|
|
15
15
|
|
|
16
16
|
import type { ConfigPath } from "../index";
|
|
17
|
-
import type {
|
|
18
|
-
|
|
17
|
+
import type {
|
|
18
|
+
CommonYargsOptions,
|
|
19
|
+
YargsOptionsToInterface,
|
|
20
|
+
} from "../yargs-types";
|
|
21
|
+
import type { Argv } from "yargs";
|
|
19
22
|
|
|
20
|
-
export const secret:
|
|
21
|
-
secretYargs: Argv
|
|
22
|
-
) => {
|
|
23
|
+
export const secret = (secretYargs: Argv<CommonYargsOptions>) => {
|
|
23
24
|
return secretYargs
|
|
24
25
|
.option("legacy-env", {
|
|
25
26
|
type: "boolean",
|
|
@@ -39,13 +40,6 @@ export const secret: BuilderCallback<unknown, unknown> = (
|
|
|
39
40
|
describe: "Name of the Worker",
|
|
40
41
|
type: "string",
|
|
41
42
|
requiresArg: true,
|
|
42
|
-
})
|
|
43
|
-
.option("env", {
|
|
44
|
-
type: "string",
|
|
45
|
-
requiresArg: true,
|
|
46
|
-
describe:
|
|
47
|
-
"Binds the secret to the Worker of the specific environment",
|
|
48
|
-
alias: "e",
|
|
49
43
|
});
|
|
50
44
|
},
|
|
51
45
|
async (args) => {
|
|
@@ -110,6 +104,7 @@ export const secret: BuilderCallback<unknown, unknown> = (
|
|
|
110
104
|
kv_namespaces: [],
|
|
111
105
|
vars: {},
|
|
112
106
|
durable_objects: { bindings: [] },
|
|
107
|
+
queues: [],
|
|
113
108
|
r2_buckets: [],
|
|
114
109
|
d1_databases: [],
|
|
115
110
|
services: [],
|
|
@@ -126,6 +121,7 @@ export const secret: BuilderCallback<unknown, unknown> = (
|
|
|
126
121
|
compatibility_flags: undefined,
|
|
127
122
|
usage_model: undefined,
|
|
128
123
|
keepVars: false, // this doesn't matter since it's a new script anyway
|
|
124
|
+
logpush: false,
|
|
129
125
|
}),
|
|
130
126
|
}
|
|
131
127
|
);
|
|
@@ -172,13 +168,6 @@ export const secret: BuilderCallback<unknown, unknown> = (
|
|
|
172
168
|
describe: "Name of the Worker",
|
|
173
169
|
type: "string",
|
|
174
170
|
requiresArg: true,
|
|
175
|
-
})
|
|
176
|
-
.option("env", {
|
|
177
|
-
type: "string",
|
|
178
|
-
requiresArg: true,
|
|
179
|
-
describe:
|
|
180
|
-
"Binds the secret to the Worker of the specific environment",
|
|
181
|
-
alias: "e",
|
|
182
171
|
});
|
|
183
172
|
},
|
|
184
173
|
async (args) => {
|
|
@@ -225,19 +214,11 @@ export const secret: BuilderCallback<unknown, unknown> = (
|
|
|
225
214
|
"list",
|
|
226
215
|
"List all secrets for a Worker",
|
|
227
216
|
(yargs) => {
|
|
228
|
-
return yargs
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
})
|
|
234
|
-
.option("env", {
|
|
235
|
-
type: "string",
|
|
236
|
-
requiresArg: true,
|
|
237
|
-
describe:
|
|
238
|
-
"Binds the secret to the Worker of the specific environment.",
|
|
239
|
-
alias: "e",
|
|
240
|
-
});
|
|
217
|
+
return yargs.option("name", {
|
|
218
|
+
describe: "Name of the Worker",
|
|
219
|
+
type: "string",
|
|
220
|
+
requiresArg: true,
|
|
221
|
+
});
|
|
241
222
|
},
|
|
242
223
|
async (args) => {
|
|
243
224
|
const config = readConfig(args.config as ConfigPath, args);
|
|
@@ -264,7 +245,7 @@ export const secret: BuilderCallback<unknown, unknown> = (
|
|
|
264
245
|
);
|
|
265
246
|
};
|
|
266
247
|
|
|
267
|
-
export const secretBulkOptions = (yargs: Argv) => {
|
|
248
|
+
export const secretBulkOptions = (yargs: Argv<CommonYargsOptions>) => {
|
|
268
249
|
return yargs
|
|
269
250
|
.positional("json", {
|
|
270
251
|
describe: `The JSON file of key-value pairs to upload, in form {"key": value, ...}`,
|
|
@@ -275,12 +256,6 @@ export const secretBulkOptions = (yargs: Argv) => {
|
|
|
275
256
|
describe: "Name of the Worker",
|
|
276
257
|
type: "string",
|
|
277
258
|
requiresArg: true,
|
|
278
|
-
})
|
|
279
|
-
.option("env", {
|
|
280
|
-
type: "string",
|
|
281
|
-
requiresArg: true,
|
|
282
|
-
describe: "Binds the secret to the Worker of the specific environment.",
|
|
283
|
-
alias: "e",
|
|
284
259
|
});
|
|
285
260
|
};
|
|
286
261
|
|
package/src/tail/index.ts
CHANGED
|
@@ -21,12 +21,15 @@ import {
|
|
|
21
21
|
} from "./createTail";
|
|
22
22
|
import type { WorkerMetadata } from "../create-worker-upload-form";
|
|
23
23
|
import type { ConfigPath } from "../index";
|
|
24
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
CommonYargsOptions,
|
|
26
|
+
YargsOptionsToInterface,
|
|
27
|
+
} from "../yargs-types";
|
|
25
28
|
import type { TailCLIFilters } from "./createTail";
|
|
26
29
|
import type { RawData } from "ws";
|
|
27
30
|
import type { Argv } from "yargs";
|
|
28
31
|
|
|
29
|
-
export function tailOptions(yargs: Argv) {
|
|
32
|
+
export function tailOptions(yargs: Argv<CommonYargsOptions>) {
|
|
30
33
|
return yargs
|
|
31
34
|
.positional("worker", {
|
|
32
35
|
describe: "Name or route of the worker to tail",
|
|
@@ -69,12 +72,6 @@ export function tailOptions(yargs: Argv) {
|
|
|
69
72
|
'Filter by the IP address the request originates from. Use "self" to filter for your own IP',
|
|
70
73
|
array: true,
|
|
71
74
|
})
|
|
72
|
-
.option("env", {
|
|
73
|
-
type: "string",
|
|
74
|
-
requiresArg: true,
|
|
75
|
-
describe: "Perform on a specific environment",
|
|
76
|
-
alias: "e",
|
|
77
|
-
})
|
|
78
75
|
.option("debug", {
|
|
79
76
|
type: "boolean",
|
|
80
77
|
hidden: true,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
2
|
+
import { fetch } from "undici";
|
|
3
|
+
import { logger } from "../logger";
|
|
4
|
+
|
|
5
|
+
const cache: Record<string, string> = {};
|
|
6
|
+
|
|
7
|
+
const usesAccessCache = new Map();
|
|
8
|
+
|
|
9
|
+
export async function domainUsesAccess(domain: string): Promise<boolean> {
|
|
10
|
+
logger.debug("Checking if domain has Access enabled:", domain);
|
|
11
|
+
|
|
12
|
+
if (usesAccessCache.has(domain)) {
|
|
13
|
+
logger.debug(
|
|
14
|
+
"Using cached Access switch for:",
|
|
15
|
+
domain,
|
|
16
|
+
usesAccessCache.get(domain)
|
|
17
|
+
);
|
|
18
|
+
return usesAccessCache.get(domain);
|
|
19
|
+
}
|
|
20
|
+
logger.debug("Access switch not cached for:", domain);
|
|
21
|
+
try {
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const cancel = setTimeout(() => {
|
|
24
|
+
logger.debug("Timed out");
|
|
25
|
+
controller.abort();
|
|
26
|
+
}, 1000);
|
|
27
|
+
|
|
28
|
+
const output = await fetch(`https://${domain}`, {
|
|
29
|
+
redirect: "manual",
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
clearTimeout(cancel);
|
|
33
|
+
const usesAccess = !!(
|
|
34
|
+
output.status === 302 &&
|
|
35
|
+
output.headers.get("location")?.includes("cloudflareaccess.com")
|
|
36
|
+
);
|
|
37
|
+
logger.debug("Caching access switch for:", domain);
|
|
38
|
+
|
|
39
|
+
usesAccessCache.set(domain, usesAccess);
|
|
40
|
+
return usesAccess;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
usesAccessCache.set(domain, false);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export async function getAccessToken(
|
|
47
|
+
domain: string
|
|
48
|
+
): Promise<string | undefined> {
|
|
49
|
+
if (!(await domainUsesAccess(domain))) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
if (cache[domain]) {
|
|
53
|
+
return cache[domain];
|
|
54
|
+
}
|
|
55
|
+
const output = await spawnSync("cloudflared", ["access", "login", domain]);
|
|
56
|
+
if (output.error) {
|
|
57
|
+
// The cloudflared binary is not installed
|
|
58
|
+
throw new Error(
|
|
59
|
+
"To use Wrangler with Cloudflare Access, please install `cloudflared` from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation"
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const stringOutput = output.stdout.toString();
|
|
63
|
+
const matches = stringOutput.match(/fetched your token:\n\n(.*)/m);
|
|
64
|
+
if (matches && matches.length >= 2) {
|
|
65
|
+
cache[domain] = matches[1];
|
|
66
|
+
return matches[1];
|
|
67
|
+
}
|
|
68
|
+
throw new Error("Failed to authenticate with Cloudflare Access");
|
|
69
|
+
}
|
package/src/worker.ts
CHANGED
|
@@ -113,6 +113,11 @@ export interface CfDurableObject {
|
|
|
113
113
|
environment?: string;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export interface CfQueue {
|
|
117
|
+
binding: string;
|
|
118
|
+
queue_name: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
116
121
|
export interface CfR2Bucket {
|
|
117
122
|
binding: string;
|
|
118
123
|
bucket_name: string;
|
|
@@ -194,6 +199,7 @@ export interface CfWorkerInit {
|
|
|
194
199
|
text_blobs: CfTextBlobBindings | undefined;
|
|
195
200
|
data_blobs: CfDataBlobBindings | undefined;
|
|
196
201
|
durable_objects: { bindings: CfDurableObject[] } | undefined;
|
|
202
|
+
queues: CfQueue[] | undefined;
|
|
197
203
|
r2_buckets: CfR2Bucket[] | undefined;
|
|
198
204
|
d1_databases: CfD1Database[] | undefined;
|
|
199
205
|
services: CfService[] | undefined;
|
|
@@ -206,6 +212,7 @@ export interface CfWorkerInit {
|
|
|
206
212
|
compatibility_flags: string[] | undefined;
|
|
207
213
|
usage_model: "bundled" | "unbound" | undefined;
|
|
208
214
|
keepVars: boolean | undefined;
|
|
215
|
+
logpush: boolean | undefined;
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
export interface CfWorkerContext {
|
package/src/yargs-types.ts
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import type { ArgumentsCamelCase, Argv } from "yargs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Yargs options included in every wrangler command.
|
|
5
|
+
*/
|
|
6
|
+
export interface CommonYargsOptions {
|
|
7
|
+
v: boolean | undefined;
|
|
8
|
+
config: string | undefined;
|
|
9
|
+
env: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
2
12
|
/**
|
|
3
13
|
* Given some Yargs Options function factory, extract the interface
|
|
4
14
|
* that corresponds to the yargs arguments
|
|
5
15
|
*/
|
|
6
|
-
export type YargsOptionsToInterface<
|
|
7
|
-
T extends (yargs: Argv) => Argv
|
|
16
|
+
export type YargsOptionsToInterface<
|
|
17
|
+
T extends (yargs: Argv<CommonYargsOptions>) => Argv
|
|
18
|
+
> = T extends (yargs: Argv<CommonYargsOptions>) => Argv<infer P>
|
|
19
|
+
? ArgumentsCamelCase<P>
|
|
20
|
+
: never;
|
package/src/zones.ts
CHANGED
|
@@ -9,12 +9,38 @@ export interface Zone {
|
|
|
9
9
|
host: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Get the hostname on which to run a Worker.
|
|
14
|
+
*
|
|
15
|
+
* The most accurate place is usually
|
|
16
|
+
* `route.pattern`, as that includes any subdomains. For example:
|
|
17
|
+
* ```js
|
|
18
|
+
* {
|
|
19
|
+
* pattern: foo.example.com
|
|
20
|
+
* zone_name: example.com
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
* However, in the case of patterns that _can't_ be parsed as a hostname
|
|
24
|
+
* (primarily the pattern `*/ /*`), we fall back to the `zone_name`
|
|
25
|
+
* (and in the absence of that throw an error).
|
|
26
|
+
* @param route
|
|
27
|
+
*/
|
|
12
28
|
export function getHostFromRoute(route: Route): string | undefined {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
29
|
+
if (typeof route === "string") {
|
|
30
|
+
return getHostFromUrl(route);
|
|
31
|
+
} else if (typeof route === "object") {
|
|
32
|
+
try {
|
|
33
|
+
return getHostFromUrl(route.pattern);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
if (
|
|
36
|
+
(e as { code: string }).code === "ERR_INVALID_URL" &&
|
|
37
|
+
"zone_name" in route
|
|
38
|
+
) {
|
|
39
|
+
return getHostFromUrl(route.zone_name);
|
|
40
|
+
}
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
18
44
|
}
|
|
19
45
|
|
|
20
46
|
/**
|
|
@@ -19,6 +19,7 @@ type EventContext<Env, P extends string, Data> = {
|
|
|
19
19
|
request: Request;
|
|
20
20
|
functionPath: string;
|
|
21
21
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
22
|
+
passThroughOnException: () => void;
|
|
22
23
|
next: (input?: Request | string, init?: RequestInit) => Promise<Response>;
|
|
23
24
|
env: Env & { ASSETS: { fetch: typeof fetch } };
|
|
24
25
|
params: Params<P>;
|
|
@@ -29,6 +30,7 @@ type EventPluginContext<Env, P extends string, Data, PluginArgs> = {
|
|
|
29
30
|
request: Request;
|
|
30
31
|
functionPath: string;
|
|
31
32
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
33
|
+
passThroughOnException: () => void;
|
|
32
34
|
next: (input?: Request | string, init?: RequestInit) => Promise<Response>;
|
|
33
35
|
env: Env & { ASSETS: { fetch: typeof fetch } };
|
|
34
36
|
params: Params<P>;
|
|
@@ -146,6 +148,8 @@ export default function (pluginArgs) {
|
|
|
146
148
|
pluginArgs,
|
|
147
149
|
env,
|
|
148
150
|
waitUntil: workerContext.waitUntil.bind(workerContext),
|
|
151
|
+
passThroughOnException:
|
|
152
|
+
workerContext.passThroughOnException.bind(workerContext),
|
|
149
153
|
};
|
|
150
154
|
|
|
151
155
|
const response = await handler(context);
|
|
@@ -19,6 +19,7 @@ type EventContext<Env, P extends string, Data> = {
|
|
|
19
19
|
request: Request;
|
|
20
20
|
functionPath: string;
|
|
21
21
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
22
|
+
passThroughOnException: () => void;
|
|
22
23
|
next: (input?: Request | string, init?: RequestInit) => Promise<Response>;
|
|
23
24
|
env: Env & { ASSETS: { fetch: typeof fetch } };
|
|
24
25
|
params: Params<P>;
|
|
@@ -53,6 +54,7 @@ type FetchEnv = {
|
|
|
53
54
|
|
|
54
55
|
type WorkerContext = {
|
|
55
56
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
57
|
+
passThroughOnException: () => void;
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
function* executeRequest(request: Request) {
|
|
@@ -111,9 +113,16 @@ function* executeRequest(request: Request) {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
export default {
|
|
114
|
-
async fetch(
|
|
116
|
+
async fetch(
|
|
117
|
+
originalRequest: Request,
|
|
118
|
+
env: FetchEnv,
|
|
119
|
+
workerContext: WorkerContext
|
|
120
|
+
) {
|
|
121
|
+
let request = originalRequest;
|
|
115
122
|
const handlerIterator = executeRequest(request);
|
|
116
123
|
const data = {}; // arbitrary data the user can set between functions
|
|
124
|
+
let isFailOpen = false;
|
|
125
|
+
|
|
117
126
|
const next = async (input?: RequestInfo, init?: RequestInit) => {
|
|
118
127
|
if (input !== undefined) {
|
|
119
128
|
let url = input;
|
|
@@ -135,6 +144,9 @@ export default {
|
|
|
135
144
|
data,
|
|
136
145
|
env,
|
|
137
146
|
waitUntil: workerContext.waitUntil.bind(workerContext),
|
|
147
|
+
passThroughOnException: () => {
|
|
148
|
+
isFailOpen = true;
|
|
149
|
+
},
|
|
138
150
|
};
|
|
139
151
|
|
|
140
152
|
const response = await handler(context);
|
|
@@ -156,9 +168,14 @@ export default {
|
|
|
156
168
|
};
|
|
157
169
|
|
|
158
170
|
try {
|
|
159
|
-
return next();
|
|
160
|
-
} catch (
|
|
161
|
-
|
|
171
|
+
return await next();
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (isFailOpen) {
|
|
174
|
+
const response = await env[__FALLBACK_SERVICE__].fetch(request);
|
|
175
|
+
return cloneResponse(response);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
throw error;
|
|
162
179
|
}
|
|
163
180
|
},
|
|
164
181
|
};
|
package/wrangler-dist/cli.d.ts
CHANGED
|
@@ -347,6 +347,17 @@ declare interface EnvironmentInheritable {
|
|
|
347
347
|
destination: string;
|
|
348
348
|
}[];
|
|
349
349
|
};
|
|
350
|
+
/**
|
|
351
|
+
* Send Trace Events from this worker to Workers Logpush.
|
|
352
|
+
*
|
|
353
|
+
* This will not configure a corresponding Logpush job automatically.
|
|
354
|
+
*
|
|
355
|
+
* For more information about Workers Logpush, see:
|
|
356
|
+
* https://blog.cloudflare.com/logpush-for-workers/
|
|
357
|
+
*
|
|
358
|
+
* @inheritable
|
|
359
|
+
*/
|
|
360
|
+
logpush: boolean | undefined;
|
|
350
361
|
}
|
|
351
362
|
|
|
352
363
|
/**
|
|
@@ -424,6 +435,37 @@ declare interface EnvironmentNonInheritable {
|
|
|
424
435
|
/** The ID of the KV namespace used during `wrangler dev` */
|
|
425
436
|
preview_id?: string;
|
|
426
437
|
}[];
|
|
438
|
+
/**
|
|
439
|
+
* Specifies Queues that are bound to this Worker environment.
|
|
440
|
+
*
|
|
441
|
+
* NOTE: This field is not automatically inherited from the top level environment,
|
|
442
|
+
* and so must be specified in every named environment.
|
|
443
|
+
*
|
|
444
|
+
* @default `{}`
|
|
445
|
+
* @nonInheritable
|
|
446
|
+
*/
|
|
447
|
+
queues: {
|
|
448
|
+
/** Producer bindings */
|
|
449
|
+
producers?: {
|
|
450
|
+
/** The binding name used to refer to the Queue in the worker. */
|
|
451
|
+
binding: string;
|
|
452
|
+
/** The name of this Queue. */
|
|
453
|
+
queue: string;
|
|
454
|
+
}[];
|
|
455
|
+
/** Consumer configuration */
|
|
456
|
+
consumers?: {
|
|
457
|
+
/** The name of the queue from which this script should consume. */
|
|
458
|
+
queue: string;
|
|
459
|
+
/** The maximum number of messages per batch */
|
|
460
|
+
max_batch_size?: number;
|
|
461
|
+
/** The maximum number of seconds to wait to fill a batch with messages. */
|
|
462
|
+
max_batch_timeout?: number;
|
|
463
|
+
/** The maximum number of retries for each message. */
|
|
464
|
+
max_retries?: number;
|
|
465
|
+
/** The queue to send messages that failed to be consumed. */
|
|
466
|
+
dead_letter_queue?: string;
|
|
467
|
+
}[];
|
|
468
|
+
};
|
|
427
469
|
/**
|
|
428
470
|
* Specifies R2 buckets that are bound to this Worker environment.
|
|
429
471
|
*
|