two-stroke 1.0.5 → 1.0.7
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/bin/test.mjs +2 -2
- package/package.json +16 -15
- package/src/index.ts +52 -14
- package/src/openAPI.ts +14 -3
- package/src/release.ts +1 -1
- package/src/test.ts +65 -3
- package/src/types.ts +18 -11
- package/tsconfig.json +3 -8
package/bin/test.mjs
CHANGED
|
@@ -9,14 +9,14 @@ if (fs.existsSync("wrangler.toml")) {
|
|
|
9
9
|
await cmd("wrangler deploy --dry-run --outdir=dist");
|
|
10
10
|
const app = await import(`${process.cwd()}/dist/index.js`);
|
|
11
11
|
const request = await app.default.fetch(
|
|
12
|
-
{ url: "http://example.com/doc
|
|
12
|
+
{ url: "http://example.com/doc", method: "GET" },
|
|
13
13
|
{ SENTRY_DSN: null, SENTRY_ENVIRONMENT: null },
|
|
14
14
|
null,
|
|
15
15
|
);
|
|
16
16
|
const types = await openapiTS(await consumers.json(request.body));
|
|
17
17
|
fs.writeFileSync("test/api.d.ts", types);
|
|
18
18
|
}
|
|
19
|
-
await cmd("vitest --globals --no-file-parallelism
|
|
19
|
+
await cmd("vitest --globals --no-file-parallelism", [
|
|
20
20
|
...(!process.argv.slice(2).includes("-w") &&
|
|
21
21
|
!process.argv.slice(2).includes("--watch")
|
|
22
22
|
? ["--run"]
|
package/package.json
CHANGED
|
@@ -9,20 +9,21 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anatine/zod-openapi": "^2.2.3",
|
|
12
|
-
"@asteasolutions/zod-to-openapi": "^6.
|
|
13
|
-
"@cloudflare/workers-types": "^4.
|
|
14
|
-
"@sentry/cli": "^2.
|
|
15
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
16
|
-
"@typescript-eslint/parser": "^7.
|
|
17
|
-
"@vitest/coverage-v8": "^1.
|
|
12
|
+
"@asteasolutions/zod-to-openapi": "^6.4.0",
|
|
13
|
+
"@cloudflare/workers-types": "^4.20240222.0",
|
|
14
|
+
"@sentry/cli": "^2.30.0",
|
|
15
|
+
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
|
16
|
+
"@typescript-eslint/parser": "^7.1.1",
|
|
17
|
+
"@vitest/coverage-v8": "^1.3.1",
|
|
18
18
|
"eslint-config-prettier": "^9.1.0",
|
|
19
19
|
"eslint-config-two-stroke": "^1.0.0",
|
|
20
20
|
"eslint-config-typescript": "^3.0.0",
|
|
21
|
+
"jose": "^5.2.3",
|
|
21
22
|
"jwk-subtle": "^1.0.6",
|
|
22
|
-
"miniflare": "^3.
|
|
23
|
-
"openapi-fetch": "^0.9.
|
|
23
|
+
"miniflare": "^3.20240223.1",
|
|
24
|
+
"openapi-fetch": "^0.9.3",
|
|
24
25
|
"openapi-typescript": "^6.7.4",
|
|
25
|
-
"openapi3-ts": "^4.2.
|
|
26
|
+
"openapi3-ts": "^4.2.2",
|
|
26
27
|
"pbkdf-subtle": "^1.0.0",
|
|
27
28
|
"toml": "^3.0.0",
|
|
28
29
|
"toucan-js": "^3.3.1",
|
|
@@ -50,13 +51,13 @@
|
|
|
50
51
|
"name": "two-stroke",
|
|
51
52
|
"packageManager": "yarn@4.1.0",
|
|
52
53
|
"type": "module",
|
|
53
|
-
"version": "1.0.
|
|
54
|
+
"version": "1.0.7",
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@types/eslint": "^8.56.
|
|
56
|
-
"@types/node": "^20.11.
|
|
57
|
-
"eslint": "^8.
|
|
56
|
+
"@types/eslint": "^8.56.5",
|
|
57
|
+
"@types/node": "^20.11.25",
|
|
58
|
+
"eslint": "^8.57.0",
|
|
58
59
|
"prettier": "^3.2.5",
|
|
59
|
-
"typescript": "^5.
|
|
60
|
-
"vitest": "^1.
|
|
60
|
+
"typescript": "^5.4.2",
|
|
61
|
+
"vitest": "^1.3.1"
|
|
61
62
|
}
|
|
62
63
|
}
|
package/src/index.ts
CHANGED
|
@@ -16,12 +16,13 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
16
16
|
env: T;
|
|
17
17
|
sentry: Toucan;
|
|
18
18
|
}) => Promise<void>;
|
|
19
|
-
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
const routes: Route<T, any>[] = [];
|
|
20
21
|
routes.push({
|
|
21
22
|
auth: noAuth,
|
|
22
23
|
method: "GET",
|
|
23
|
-
path: "/doc
|
|
24
|
-
matcher: /^\/doc
|
|
24
|
+
path: "/doc",
|
|
25
|
+
matcher: /^\/doc$/,
|
|
25
26
|
output: z.object({}),
|
|
26
27
|
handler: openAPI(title, release, noAuth, routes),
|
|
27
28
|
});
|
|
@@ -53,6 +54,17 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
53
54
|
release,
|
|
54
55
|
});
|
|
55
56
|
try {
|
|
57
|
+
if (req.method == "OPTIONS") {
|
|
58
|
+
return new Response("", {
|
|
59
|
+
status: 204,
|
|
60
|
+
headers: {
|
|
61
|
+
"Access-Control-Allow-Origin": "*",
|
|
62
|
+
"Access-Control-Max-Age": "86400",
|
|
63
|
+
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE",
|
|
64
|
+
"Access-Control-Allow-Headers": "Authorization,Content-Type",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
56
68
|
const { pathname } = new URL(req.url);
|
|
57
69
|
let response;
|
|
58
70
|
for (const route of routes) {
|
|
@@ -68,6 +80,7 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
68
80
|
statusText: "Invalid Authorization",
|
|
69
81
|
headers: {
|
|
70
82
|
"WWW-Authenticate": "Bearer",
|
|
83
|
+
"Access-Control-Allow-Origin": "*",
|
|
71
84
|
},
|
|
72
85
|
});
|
|
73
86
|
}
|
|
@@ -89,10 +102,23 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
89
102
|
sentry,
|
|
90
103
|
});
|
|
91
104
|
else {
|
|
92
|
-
console.error(
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
console.error({
|
|
106
|
+
message: "Request body schema invalid",
|
|
107
|
+
error: body.error,
|
|
108
|
+
body: rawBody,
|
|
95
109
|
});
|
|
110
|
+
return new Response(
|
|
111
|
+
JSON.stringify({
|
|
112
|
+
error: "Request body schema invalid",
|
|
113
|
+
...body.error,
|
|
114
|
+
}),
|
|
115
|
+
{
|
|
116
|
+
status: 400,
|
|
117
|
+
headers: {
|
|
118
|
+
"Access-Control-Allow-Origin": "*",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
);
|
|
96
122
|
}
|
|
97
123
|
} else {
|
|
98
124
|
response = await route.handler({
|
|
@@ -105,13 +131,21 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
105
131
|
sentry,
|
|
106
132
|
});
|
|
107
133
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
134
|
+
if (response.status === undefined || response.status == 200) {
|
|
135
|
+
const output = route.output.safeParse(response.body);
|
|
136
|
+
if (!output.success) {
|
|
137
|
+
console.error({
|
|
138
|
+
message: "Response body schema invalid",
|
|
139
|
+
error: output.error,
|
|
140
|
+
body: response.body,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
111
143
|
}
|
|
112
144
|
response.headers = response.headers ?? {};
|
|
113
145
|
response.headers["Content-Type"] =
|
|
114
146
|
response.headers["Content-Type"] ?? "application/json";
|
|
147
|
+
response.headers["Access-Control-Allow-Origin"] =
|
|
148
|
+
response.headers["Access-Control-Allow-Origin"] ?? "*";
|
|
115
149
|
return new Response(
|
|
116
150
|
response.headers["Content-Type"] == "application/json"
|
|
117
151
|
? JSON.stringify(response.body)
|
|
@@ -120,13 +154,17 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
120
154
|
);
|
|
121
155
|
}
|
|
122
156
|
}
|
|
123
|
-
return new Response("", {
|
|
157
|
+
return new Response("", {
|
|
158
|
+
status: 404,
|
|
159
|
+
headers: { "Access-Control-Allow-Origin": "*" },
|
|
160
|
+
});
|
|
124
161
|
} catch (err) {
|
|
125
162
|
console.warn(err);
|
|
126
163
|
sentry.captureException(err);
|
|
127
164
|
return new Response("", {
|
|
128
165
|
status: 500,
|
|
129
166
|
statusText: "Internal Server Error",
|
|
167
|
+
headers: { "Access-Control-Allow-Origin": "*" },
|
|
130
168
|
});
|
|
131
169
|
}
|
|
132
170
|
},
|
|
@@ -250,7 +288,7 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
250
288
|
};
|
|
251
289
|
},
|
|
252
290
|
put<I extends ZodSchema, O extends ZodSchema, A, P extends string>(
|
|
253
|
-
auth: Route<T>["auth"],
|
|
291
|
+
auth: Route<T, A>["auth"],
|
|
254
292
|
path: P,
|
|
255
293
|
input: I,
|
|
256
294
|
output: O,
|
|
@@ -277,7 +315,7 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
277
315
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
278
316
|
PP extends ZodObject<any> | undefined,
|
|
279
317
|
>(
|
|
280
|
-
auth: Route<T>["auth"],
|
|
318
|
+
auth: Route<T, A>["auth"],
|
|
281
319
|
path: P,
|
|
282
320
|
input: I,
|
|
283
321
|
output: O,
|
|
@@ -305,7 +343,7 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
305
343
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
306
344
|
PP extends ZodObject<any> | undefined,
|
|
307
345
|
>(
|
|
308
|
-
auth: Route<T>["auth"],
|
|
346
|
+
auth: Route<T, A>["auth"],
|
|
309
347
|
path: P,
|
|
310
348
|
output: O,
|
|
311
349
|
handler: Handler<T, undefined, O, A, P>,
|
|
@@ -324,7 +362,7 @@ export function twoStroke<T extends Env>(title: string, release: string) {
|
|
|
324
362
|
});
|
|
325
363
|
},
|
|
326
364
|
delete<O extends ZodSchema, A, P extends string>(
|
|
327
|
-
auth: Route<T>["auth"],
|
|
365
|
+
auth: Route<T, A>["auth"],
|
|
328
366
|
path: P,
|
|
329
367
|
output: O,
|
|
330
368
|
handler: Handler<T, undefined, O, A, P>,
|
package/src/openAPI.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Env, Route } from "./types";
|
|
|
7
7
|
import { ZodIssue, ZodType, z } from "zod";
|
|
8
8
|
|
|
9
9
|
const ZodErrorSchema: ZodType<{ issues: ZodIssue[] }> = z.object({
|
|
10
|
+
error: z.string(),
|
|
10
11
|
issues: z.array(
|
|
11
12
|
z.object({
|
|
12
13
|
code: z.literal("invalid_literal"),
|
|
@@ -31,11 +32,11 @@ type Method =
|
|
|
31
32
|
extendZodWithOpenApi(z);
|
|
32
33
|
|
|
33
34
|
export const openAPI =
|
|
34
|
-
<T extends Env>(
|
|
35
|
+
<T extends Env, A>(
|
|
35
36
|
title: string,
|
|
36
37
|
release: string,
|
|
37
|
-
noAuth: () =>
|
|
38
|
-
routes: Route<T>[],
|
|
38
|
+
noAuth: () => A,
|
|
39
|
+
routes: Route<T, A>[],
|
|
39
40
|
) =>
|
|
40
41
|
async () => {
|
|
41
42
|
const openAPIRegistry = new OpenAPIRegistry();
|
|
@@ -88,6 +89,16 @@ export const openAPI =
|
|
|
88
89
|
},
|
|
89
90
|
},
|
|
90
91
|
},
|
|
92
|
+
500: {
|
|
93
|
+
description: "Invalid Request",
|
|
94
|
+
content: {
|
|
95
|
+
"application/json": {
|
|
96
|
+
schema: z.object({
|
|
97
|
+
error: z.string(),
|
|
98
|
+
}),
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
91
102
|
},
|
|
92
103
|
});
|
|
93
104
|
});
|
package/src/release.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default "undefined";
|
|
1
|
+
export default "undefined";
|
package/src/test.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Env } from "./types";
|
|
|
5
5
|
import consumers from "stream/consumers";
|
|
6
6
|
import { URLSearchParams } from "url";
|
|
7
7
|
import createClient from "openapi-fetch";
|
|
8
|
+
import { generateKeyPair, SignJWT, JWTPayload, exportJWK } from "jose";
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
10
11
|
export const setupTests = async <Paths extends {}>(bindings: Env) => {
|
|
@@ -41,6 +42,14 @@ export const setupTests = async <Paths extends {}>(bindings: Env) => {
|
|
|
41
42
|
d1Databases: (config.d1_databases ?? []).map(
|
|
42
43
|
({ binding }: { binding: string }) => binding,
|
|
43
44
|
),
|
|
45
|
+
serviceBindings: Object.fromEntries(
|
|
46
|
+
(config.services ?? []).map(
|
|
47
|
+
({ binding, service }: { binding: string; service: string }) => [
|
|
48
|
+
binding,
|
|
49
|
+
service,
|
|
50
|
+
],
|
|
51
|
+
),
|
|
52
|
+
),
|
|
44
53
|
fetchMock,
|
|
45
54
|
});
|
|
46
55
|
|
|
@@ -65,6 +74,50 @@ export const setupTests = async <Paths extends {}>(bindings: Env) => {
|
|
|
65
74
|
await waitUntil(() => expect(log).contains("Queue batch finished"));
|
|
66
75
|
console.log = orig;
|
|
67
76
|
},
|
|
77
|
+
async fakeJWK(issuer: string, audience: string, claims: JWTPayload) {
|
|
78
|
+
const { publicKey, privateKey } = await generateKeyPair("RS256");
|
|
79
|
+
const jwk = await exportJWK(publicKey);
|
|
80
|
+
jwk.kid = "test";
|
|
81
|
+
jwk.alg = "RS256";
|
|
82
|
+
fetchMock
|
|
83
|
+
.get(bindings[issuer] as string)
|
|
84
|
+
.intercept({ method: "GET", path: "/.well-known/openid-configuration" })
|
|
85
|
+
.reply(
|
|
86
|
+
200,
|
|
87
|
+
{
|
|
88
|
+
jwks_uri: `${bindings[issuer]}/.well-known/jwks`,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
headers: {
|
|
92
|
+
"Content-Type": "application/json",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
.persist();
|
|
97
|
+
fetchMock
|
|
98
|
+
.get(bindings[issuer] as string)
|
|
99
|
+
.intercept({ method: "GET", path: "/.well-known/jwks" })
|
|
100
|
+
.reply(
|
|
101
|
+
200,
|
|
102
|
+
{
|
|
103
|
+
keys: [jwk],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
headers: {
|
|
107
|
+
"Content-Type": "application/json",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
.persist();
|
|
112
|
+
return await new SignJWT(claims)
|
|
113
|
+
.setProtectedHeader({ typ: "JWT", alg: "RS256", kid: jwk.kid })
|
|
114
|
+
.setIssuedAt()
|
|
115
|
+
.setNotBefore("5 minutes ago")
|
|
116
|
+
.setIssuer(bindings[issuer] as string)
|
|
117
|
+
.setAudience([bindings[audience] as string])
|
|
118
|
+
.setExpirationTime("1h")
|
|
119
|
+
.sign(privateKey);
|
|
120
|
+
},
|
|
68
121
|
};
|
|
69
122
|
};
|
|
70
123
|
|
|
@@ -83,11 +136,14 @@ export function recordRequest(
|
|
|
83
136
|
cb: (data: any) => void,
|
|
84
137
|
statusCode: number,
|
|
85
138
|
data: string | object | Buffer | undefined,
|
|
139
|
+
responseOptions?: {
|
|
140
|
+
headers: Record<string, string | string[] | undefined>;
|
|
141
|
+
},
|
|
86
142
|
) {
|
|
87
143
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
144
|
return ({ body }: any) => {
|
|
89
145
|
consumers.json(body).then(cb);
|
|
90
|
-
return { statusCode, data };
|
|
146
|
+
return { statusCode, data, responseOptions };
|
|
91
147
|
};
|
|
92
148
|
}
|
|
93
149
|
|
|
@@ -96,6 +152,9 @@ export function recordFormRequest(
|
|
|
96
152
|
cb: (data: any) => void,
|
|
97
153
|
statusCode: number,
|
|
98
154
|
data: string | object | Buffer | undefined,
|
|
155
|
+
responseOptions?: {
|
|
156
|
+
headers: Record<string, string | string[] | undefined>;
|
|
157
|
+
},
|
|
99
158
|
) {
|
|
100
159
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
160
|
return ({ body }: any) => {
|
|
@@ -105,7 +164,7 @@ export function recordFormRequest(
|
|
|
105
164
|
.then((data: any) =>
|
|
106
165
|
cb(Object.fromEntries(new URLSearchParams(data).entries())),
|
|
107
166
|
);
|
|
108
|
-
return { statusCode, data };
|
|
167
|
+
return { statusCode, data, responseOptions };
|
|
109
168
|
};
|
|
110
169
|
}
|
|
111
170
|
|
|
@@ -114,6 +173,9 @@ export function recordFirehoseRequest(
|
|
|
114
173
|
cb: (data: any) => void,
|
|
115
174
|
statusCode: number,
|
|
116
175
|
data: string | object | Buffer | undefined,
|
|
176
|
+
responseOptions?: {
|
|
177
|
+
headers: Record<string, string | string[] | undefined>;
|
|
178
|
+
},
|
|
117
179
|
) {
|
|
118
180
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
181
|
return ({ body }: any) => {
|
|
@@ -121,6 +183,6 @@ export function recordFirehoseRequest(
|
|
|
121
183
|
.json(body)
|
|
122
184
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
185
|
.then((data: any) => cb(JSON.parse(atob(data["Record"]["Data"]))));
|
|
124
|
-
return { statusCode, data };
|
|
186
|
+
return { statusCode, data, responseOptions };
|
|
125
187
|
};
|
|
126
188
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import { Toucan } from "toucan-js";
|
|
2
2
|
import { ZodObject, ZodSchema, z } from "zod";
|
|
3
3
|
export type Env = {
|
|
4
|
-
[k: string]: string | Queue | KVNamespace | R2Bucket | D1Database;
|
|
4
|
+
[k: string]: string | Queue | KVNamespace | R2Bucket | D1Database | Fetcher;
|
|
5
5
|
};
|
|
6
|
-
export type Route<T extends Env> =
|
|
6
|
+
export type Route<T extends Env, A> =
|
|
7
7
|
| {
|
|
8
|
-
auth: (c: { req: Request; env: T }) =>
|
|
8
|
+
auth: (c: { req: Request; env: T }) => Promise<A>;
|
|
9
9
|
method: "GET" | "DELETE";
|
|
10
10
|
path: string;
|
|
11
11
|
matcher: RegExp;
|
|
12
12
|
output: ZodSchema;
|
|
13
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
-
handler: Handler<T, undefined, any,
|
|
14
|
+
handler: Handler<T, undefined, any, A, string>;
|
|
15
15
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
16
|
params?: ZodObject<any>;
|
|
17
17
|
}
|
|
18
18
|
| {
|
|
19
|
-
auth: (c: { req: Request; env: T }) =>
|
|
19
|
+
auth: (c: { req: Request; env: T }) => Promise<A>;
|
|
20
20
|
method: "POST" | "PUT";
|
|
21
21
|
path: string;
|
|
22
22
|
matcher: RegExp;
|
|
23
23
|
input: ZodSchema;
|
|
24
24
|
output: ZodSchema;
|
|
25
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
-
handler: Handler<T, any, any,
|
|
26
|
+
handler: Handler<T, any, any, A, string>;
|
|
27
27
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
28
|
params?: ZodObject<any>;
|
|
29
29
|
};
|
|
@@ -47,8 +47,15 @@ export type Handler<
|
|
|
47
47
|
searchParams: URLSearchParams;
|
|
48
48
|
claims: A;
|
|
49
49
|
sentry: Toucan;
|
|
50
|
-
}) => Promise<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
}) => Promise<
|
|
51
|
+
| {
|
|
52
|
+
body: z.infer<O>;
|
|
53
|
+
status?: 200;
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
body?: { error: string };
|
|
58
|
+
status: number;
|
|
59
|
+
headers?: Record<string, string>;
|
|
60
|
+
}
|
|
61
|
+
>;
|
package/tsconfig.json
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"esModuleInterop": true,
|
|
4
4
|
"isolatedModules": true,
|
|
5
|
-
"lib": [
|
|
6
|
-
"ESNext"
|
|
7
|
-
],
|
|
5
|
+
"lib": ["ESNext"],
|
|
8
6
|
"module": "ESNext",
|
|
9
7
|
"moduleResolution": "bundler",
|
|
10
8
|
"noUncheckedIndexedAccess": true,
|
|
@@ -12,9 +10,6 @@
|
|
|
12
10
|
"skipLibCheck": true,
|
|
13
11
|
"strict": true,
|
|
14
12
|
"target": "ESNext",
|
|
15
|
-
"types": [
|
|
16
|
-
"@cloudflare/workers-types",
|
|
17
|
-
"vitest/globals"
|
|
18
|
-
]
|
|
13
|
+
"types": ["@cloudflare/workers-types", "vitest/globals"]
|
|
19
14
|
}
|
|
20
|
-
}
|
|
15
|
+
}
|