wrangler 2.1.13 → 2.1.15
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 +0 -4
- package/miniflare-dist/index.mjs +11 -7
- package/package.json +2 -1
- package/src/__tests__/delete.test.ts +114 -0
- package/src/__tests__/deployments.test.ts +91 -0
- package/src/__tests__/helpers/msw/handlers/deployments.ts +80 -0
- package/src/__tests__/helpers/msw/index.ts +4 -2
- package/src/__tests__/index.test.ts +4 -2
- package/src/__tests__/init.test.ts +1 -1
- package/src/__tests__/pages.test.ts +110 -0
- package/src/__tests__/tail.test.ts +2 -2
- package/src/__tests__/type-generation.test.ts +217 -0
- package/src/delete.ts +26 -1
- package/src/dev/local.tsx +5 -0
- package/src/entry.ts +1 -1
- package/src/index.tsx +88 -2
- package/src/init.ts +1 -1
- package/src/is-interactive.ts +4 -0
- package/src/logger.ts +2 -2
- package/src/miniflare-cli/index.ts +13 -8
- package/src/pages/constants.ts +2 -0
- package/src/pages/dev.tsx +4 -0
- package/src/pages/upload.tsx +23 -13
- package/src/sites.tsx +1 -1
- package/src/type-generation.ts +159 -0
- package/templates/__tests__/pages-dev-util.test.ts +128 -0
- package/templates/pages-dev-pipeline.ts +5 -12
- package/templates/pages-dev-util.ts +52 -0
- package/templates/pages-template-plugin.ts +4 -0
- package/templates/pages-template-worker.ts +21 -4
- package/templates/tsconfig.json +2 -1
- package/wrangler-dist/cli.js +7857 -6920
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { findUpSync } from "find-up";
|
|
3
|
+
import { getEntry } from "./entry";
|
|
4
|
+
import { logger } from "./logger";
|
|
5
|
+
import type { Config } from "./config";
|
|
6
|
+
import type { CfWorkerInit } from "./worker";
|
|
7
|
+
|
|
8
|
+
// Currently includes bindings & rules for declaring modules
|
|
9
|
+
export type PartialConfigToDTS = CfWorkerInit["bindings"] & {
|
|
10
|
+
rules: Config["rules"];
|
|
11
|
+
};
|
|
12
|
+
export async function generateTypes(
|
|
13
|
+
configToDTS: PartialConfigToDTS,
|
|
14
|
+
config: Config
|
|
15
|
+
) {
|
|
16
|
+
const entry = await getEntry({}, config, "types");
|
|
17
|
+
const envTypeStructure: string[] = [];
|
|
18
|
+
|
|
19
|
+
if (configToDTS.kv_namespaces) {
|
|
20
|
+
for (const kvNamespace of configToDTS.kv_namespaces) {
|
|
21
|
+
envTypeStructure.push(` ${kvNamespace.binding}: KVNamespace;`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (configToDTS.vars) {
|
|
26
|
+
for (const varName in configToDTS.vars) {
|
|
27
|
+
const varValue = configToDTS.vars[varName];
|
|
28
|
+
if (
|
|
29
|
+
typeof varValue === "string" ||
|
|
30
|
+
typeof varValue === "number" ||
|
|
31
|
+
typeof varValue === "boolean"
|
|
32
|
+
) {
|
|
33
|
+
envTypeStructure.push(` ${varName}: ${varValue};`);
|
|
34
|
+
}
|
|
35
|
+
if (typeof varValue === "object" && varValue !== null) {
|
|
36
|
+
envTypeStructure.push(` ${varName}: ${JSON.stringify(varValue)};`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (configToDTS.durable_objects?.bindings) {
|
|
42
|
+
for (const durableObject of configToDTS.durable_objects.bindings) {
|
|
43
|
+
envTypeStructure.push(` ${durableObject.name}: DurableObjectNamespace;`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (configToDTS.r2_buckets) {
|
|
48
|
+
for (const R2Bucket of configToDTS.r2_buckets) {
|
|
49
|
+
envTypeStructure.push(` ${R2Bucket.binding}: R2Bucket;`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (configToDTS.d1_databases) {
|
|
54
|
+
for (const d1 of configToDTS.d1_databases) {
|
|
55
|
+
envTypeStructure.push(` ${d1.binding}: D1Database;`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (configToDTS.services) {
|
|
60
|
+
for (const service of configToDTS.services) {
|
|
61
|
+
envTypeStructure.push(` ${service.binding}: Fetcher;`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (configToDTS.dispatch_namespaces) {
|
|
66
|
+
for (const namespace of configToDTS.dispatch_namespaces) {
|
|
67
|
+
envTypeStructure.push(` ${namespace.binding}: any;`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (configToDTS.logfwdr?.schema) {
|
|
72
|
+
envTypeStructure.push(` LOGFWDR_SCHEMA: any;`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (configToDTS.data_blobs) {
|
|
76
|
+
for (const dataBlobs in configToDTS.data_blobs) {
|
|
77
|
+
envTypeStructure.push(` ${dataBlobs}: ArrayBuffer;`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (configToDTS.text_blobs) {
|
|
82
|
+
for (const textBlobs in configToDTS.text_blobs) {
|
|
83
|
+
envTypeStructure.push(` ${textBlobs}: string;`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (configToDTS.unsafe) {
|
|
88
|
+
for (const unsafe of configToDTS.unsafe) {
|
|
89
|
+
envTypeStructure.push(` ${unsafe.name}: any;`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const modulesTypeStructure: string[] = [];
|
|
94
|
+
if (configToDTS.rules) {
|
|
95
|
+
const moduleTypeMap = {
|
|
96
|
+
Text: "string",
|
|
97
|
+
Data: "ArrayBuffer",
|
|
98
|
+
CompiledWasm: "WebAssembly.Module",
|
|
99
|
+
};
|
|
100
|
+
for (const ruleObject of configToDTS.rules) {
|
|
101
|
+
const typeScriptType =
|
|
102
|
+
moduleTypeMap[ruleObject.type as keyof typeof moduleTypeMap];
|
|
103
|
+
if (typeScriptType !== undefined) {
|
|
104
|
+
ruleObject.globs.forEach((glob) => {
|
|
105
|
+
modulesTypeStructure.push(`declare module "*.${glob
|
|
106
|
+
.split(".")
|
|
107
|
+
.at(-1)}" {
|
|
108
|
+
const value: ${typeScriptType};
|
|
109
|
+
export default value;
|
|
110
|
+
}`);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function writeDTSFile(
|
|
117
|
+
typesString: string[],
|
|
118
|
+
formatType: "modules" | "service-worker"
|
|
119
|
+
) {
|
|
120
|
+
const wranglerOverrideDTSPath = findUpSync("worker-configuration.d.ts");
|
|
121
|
+
try {
|
|
122
|
+
if (
|
|
123
|
+
wranglerOverrideDTSPath !== undefined &&
|
|
124
|
+
!fs
|
|
125
|
+
.readFileSync(wranglerOverrideDTSPath, "utf8")
|
|
126
|
+
.includes("***AUTO GENERATED BY WORKERS CLI WRANGLER***")
|
|
127
|
+
) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
"A non-wrangler worker-configuration.d.ts already exists, please rename and try again."
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error instanceof Error && !error.message.includes("not found")) {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let combinedTypeStrings = "";
|
|
139
|
+
if (formatType === "modules") {
|
|
140
|
+
combinedTypeStrings = `interface Env {\n${typesString.join(
|
|
141
|
+
"\n"
|
|
142
|
+
)} \n}\n${modulesTypeStructure.join("\n")}`;
|
|
143
|
+
} else {
|
|
144
|
+
combinedTypeStrings = `declare global {\n${typesString.join(
|
|
145
|
+
"\n"
|
|
146
|
+
)} \n}\n${modulesTypeStructure.join("\n")}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (envTypeStructure.length || modulesTypeStructure.length) {
|
|
150
|
+
fs.writeFileSync(
|
|
151
|
+
"worker-configuration.d.ts",
|
|
152
|
+
`// Generated by Wrangler on ${new Date()}` + "\n" + combinedTypeStrings
|
|
153
|
+
);
|
|
154
|
+
logger.log(combinedTypeStrings);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
writeDTSFile(envTypeStructure, entry.format);
|
|
159
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { isRoutingRuleMatch } from "../pages-dev-util";
|
|
2
|
+
|
|
3
|
+
describe("isRoutingRuleMatch", () => {
|
|
4
|
+
it("should match rules referencing root level correctly", () => {
|
|
5
|
+
const routingRule = "/";
|
|
6
|
+
|
|
7
|
+
expect(isRoutingRuleMatch("/", routingRule)).toBeTruthy();
|
|
8
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeFalsy();
|
|
9
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeFalsy();
|
|
10
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeFalsy();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should match include-all rules correctly", () => {
|
|
14
|
+
const routingRule = "/*";
|
|
15
|
+
|
|
16
|
+
expect(isRoutingRuleMatch("/", routingRule)).toBeTruthy();
|
|
17
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
18
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
19
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
20
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
21
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
22
|
+
expect(isRoutingRuleMatch("/foo/bar/baz/", routingRule)).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should match `/*` suffix-ed rules correctly", () => {
|
|
26
|
+
let routingRule = "/foo/*";
|
|
27
|
+
|
|
28
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
29
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
30
|
+
expect(isRoutingRuleMatch("/foobar", routingRule)).toBeFalsy();
|
|
31
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
32
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
33
|
+
expect(isRoutingRuleMatch("/bar/foo", routingRule)).toBeFalsy();
|
|
34
|
+
expect(isRoutingRuleMatch("/bar/foo/baz", routingRule)).toBeFalsy();
|
|
35
|
+
|
|
36
|
+
routingRule = "/foo/bar/*";
|
|
37
|
+
|
|
38
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeFalsy();
|
|
39
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeFalsy();
|
|
40
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
41
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
42
|
+
expect(isRoutingRuleMatch("/foo/barfoo", routingRule)).toBeFalsy();
|
|
43
|
+
expect(isRoutingRuleMatch("baz/foo/bar", routingRule)).toBeFalsy();
|
|
44
|
+
expect(isRoutingRuleMatch("baz/foo/bar/", routingRule)).toBeFalsy();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should match `/` suffix-ed rules correctly", () => {
|
|
48
|
+
let routingRule = "/foo/";
|
|
49
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
50
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
51
|
+
|
|
52
|
+
routingRule = "/foo/bar/";
|
|
53
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
54
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should match `*` suffix-ed rules correctly", () => {
|
|
58
|
+
let routingRule = "/foo*";
|
|
59
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
60
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
61
|
+
expect(isRoutingRuleMatch("/foobar", routingRule)).toBeTruthy();
|
|
62
|
+
expect(isRoutingRuleMatch("/barfoo", routingRule)).toBeFalsy();
|
|
63
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
64
|
+
expect(isRoutingRuleMatch("/bar/foo", routingRule)).toBeFalsy();
|
|
65
|
+
expect(isRoutingRuleMatch("/bar/foobar", routingRule)).toBeFalsy();
|
|
66
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
67
|
+
expect(isRoutingRuleMatch("/bar/foo/baz", routingRule)).toBeFalsy();
|
|
68
|
+
|
|
69
|
+
routingRule = "/foo/bar*";
|
|
70
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
71
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
72
|
+
expect(isRoutingRuleMatch("/foo/barfoo", routingRule)).toBeTruthy();
|
|
73
|
+
expect(isRoutingRuleMatch("/bar/foo/barfoo", routingRule)).toBeFalsy();
|
|
74
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeTruthy();
|
|
75
|
+
expect(isRoutingRuleMatch("/bar/foo/bar/baz", routingRule)).toBeFalsy();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should match rules without wildcards correctly", () => {
|
|
79
|
+
let routingRule = "/foo";
|
|
80
|
+
|
|
81
|
+
expect(isRoutingRuleMatch("/foo", routingRule)).toBeTruthy();
|
|
82
|
+
expect(isRoutingRuleMatch("/foo/", routingRule)).toBeTruthy();
|
|
83
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeFalsy();
|
|
84
|
+
expect(isRoutingRuleMatch("/bar/foo", routingRule)).toBeFalsy();
|
|
85
|
+
|
|
86
|
+
routingRule = "/foo/bar";
|
|
87
|
+
expect(isRoutingRuleMatch("/foo/bar", routingRule)).toBeTruthy();
|
|
88
|
+
expect(isRoutingRuleMatch("/foo/bar/", routingRule)).toBeTruthy();
|
|
89
|
+
expect(isRoutingRuleMatch("/foo/bar/baz", routingRule)).toBeFalsy();
|
|
90
|
+
expect(isRoutingRuleMatch("/baz/foo/bar", routingRule)).toBeFalsy();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should throw an error if pathname or routing rule params are missing", () => {
|
|
94
|
+
// MISSING PATHNAME
|
|
95
|
+
expect(() =>
|
|
96
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
97
|
+
// @ts-ignore: sanity check
|
|
98
|
+
isRoutingRuleMatch(undefined, "/*")
|
|
99
|
+
).toThrow("Pathname is undefined.");
|
|
100
|
+
|
|
101
|
+
expect(() =>
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
103
|
+
// @ts-ignore: sanity check
|
|
104
|
+
isRoutingRuleMatch(null, "/*")
|
|
105
|
+
).toThrow("Pathname is undefined.");
|
|
106
|
+
|
|
107
|
+
expect(() => isRoutingRuleMatch("", "/*")).toThrow(
|
|
108
|
+
"Pathname is undefined."
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// MISSING ROUTING RULE
|
|
112
|
+
expect(() =>
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
114
|
+
// @ts-ignore: sanity check
|
|
115
|
+
isRoutingRuleMatch("/foo", undefined)
|
|
116
|
+
).toThrow("Routing rule is undefined.");
|
|
117
|
+
|
|
118
|
+
expect(() =>
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
120
|
+
// @ts-ignore: sanity check
|
|
121
|
+
isRoutingRuleMatch("/foo", null)
|
|
122
|
+
).toThrow("Routing rule is undefined.");
|
|
123
|
+
|
|
124
|
+
expect(() => isRoutingRuleMatch("/foo", "")).toThrow(
|
|
125
|
+
"Routing rule is undefined."
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -2,30 +2,23 @@
|
|
|
2
2
|
import worker from "__ENTRY_POINT__";
|
|
3
3
|
// @ts-ignore entry point will get replaced
|
|
4
4
|
export * from "__ENTRY_POINT__";
|
|
5
|
+
import { isRoutingRuleMatch } from "./pages-dev-util";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const routes = {
|
|
11
|
-
// @ts-ignore routes are injected
|
|
12
|
-
include: __ROUTES__.include.map(transformToRegex),
|
|
13
|
-
// @ts-ignore routes are injected
|
|
14
|
-
exclude: __ROUTES__.exclude.map(transformToRegex) || [],
|
|
15
|
-
};
|
|
7
|
+
// @ts-ignore routes are injected
|
|
8
|
+
const routes = __ROUTES__;
|
|
16
9
|
|
|
17
10
|
export default {
|
|
18
11
|
fetch(request, env, context) {
|
|
19
12
|
const { pathname } = new URL(request.url);
|
|
20
13
|
|
|
21
14
|
for (const exclude of routes.exclude) {
|
|
22
|
-
if (pathname
|
|
15
|
+
if (isRoutingRuleMatch(pathname, exclude)) {
|
|
23
16
|
return env.ASSETS.fetch(request);
|
|
24
17
|
}
|
|
25
18
|
}
|
|
26
19
|
|
|
27
20
|
for (const include of routes.include) {
|
|
28
|
-
if (pathname
|
|
21
|
+
if (isRoutingRuleMatch(pathname, include)) {
|
|
29
22
|
return worker.fetch(request, env, context);
|
|
30
23
|
}
|
|
31
24
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param pathname A pathname string, such as `/foo` or `/foo/bar`
|
|
3
|
+
* @param routingRule The routing rule, such as `/foo/*`
|
|
4
|
+
* @returns True if pathname matches the routing rule
|
|
5
|
+
*
|
|
6
|
+
* / -> /
|
|
7
|
+
* /* -> /*
|
|
8
|
+
* /foo -> /foo
|
|
9
|
+
* /foo* -> /foo, /foo-bar, /foo/*
|
|
10
|
+
* /foo/* -> /foo, /foo/bar
|
|
11
|
+
*/
|
|
12
|
+
export function isRoutingRuleMatch(
|
|
13
|
+
pathname: string,
|
|
14
|
+
routingRule: string
|
|
15
|
+
): boolean {
|
|
16
|
+
// sanity checks
|
|
17
|
+
if (!pathname) {
|
|
18
|
+
throw new Error("Pathname is undefined.");
|
|
19
|
+
}
|
|
20
|
+
if (!routingRule) {
|
|
21
|
+
throw new Error("Routing rule is undefined.");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ruleRegExp = transformRoutingRuleToRegExp(routingRule);
|
|
25
|
+
return pathname.match(ruleRegExp) !== null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function transformRoutingRuleToRegExp(rule: string): RegExp {
|
|
29
|
+
let transformedRule;
|
|
30
|
+
|
|
31
|
+
if (rule === "/" || rule === "/*") {
|
|
32
|
+
transformedRule = rule;
|
|
33
|
+
} else if (rule.endsWith("/*")) {
|
|
34
|
+
// make `/*` an optional group so we can match both /foo/* and /foo
|
|
35
|
+
// /foo/* => /foo(/*)?
|
|
36
|
+
transformedRule = `${rule.substring(0, rule.length - 2)}(/*)?`;
|
|
37
|
+
} else if (rule.endsWith("/")) {
|
|
38
|
+
// make `/` an optional group so we can match both /foo/ and /foo
|
|
39
|
+
// /foo/ => /foo(/)?
|
|
40
|
+
transformedRule = `${rule.substring(0, rule.length - 1)}(/)?`;
|
|
41
|
+
} else if (rule.endsWith("*")) {
|
|
42
|
+
transformedRule = rule;
|
|
43
|
+
} else {
|
|
44
|
+
transformedRule = `${rule}(/)?`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// /foo* => /foo.* => ^/foo.*$
|
|
48
|
+
transformedRule = `^${transformedRule.replace("*", ".*")}$`;
|
|
49
|
+
|
|
50
|
+
// ^/foo.*$ => /^\/foo.*$/
|
|
51
|
+
return new RegExp(transformedRule);
|
|
52
|
+
}
|
|
@@ -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/templates/tsconfig.json
CHANGED
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
|
35
35
|
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
|
36
36
|
"types": [
|
|
37
|
-
"@cloudflare/workers-types"
|
|
37
|
+
"@cloudflare/workers-types",
|
|
38
|
+
"jest"
|
|
38
39
|
] /* Specify type package names to be included without being referenced in a source file. */,
|
|
39
40
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
40
41
|
"resolveJsonModule": true /* Enable importing .json files */,
|